WinForm 学习总结–(页面布局、MDI)

一、MDI 窗体(多文档界面)

MDI(Multiple-Document Interface)允许在一个父窗体中同时打开、显示和管理多个子窗体。

1.1 关键属性与方法

成员 说明
IsMdiContainer 将窗体设置为 MDI 父容器(必须在设计器或代码中设为 true
MdiParent 设置子窗体的父窗体
MdiChildren 获取父窗体包含的所有子窗体数组
LayoutMdi(MdiLayout) 设置子窗体的排列方式(层叠、水平平铺、垂直平铺)
Activate() 激活并聚焦指定子窗体

1.2 MDI 子窗体排列方式

枚举值 说明
MdiLayout.Cascade 层叠排列
MdiLayout.TileHorizontal 水平平铺
MdiLayout.TileVertical 垂直平铺
MdiLayout.ArrangeIcons 排列图标

1.3 代码示例

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    /// <summary>
    /// 同时打开多个子窗体并设置垂直平铺布局
    /// </summary>
    private void 打开窗体ToolStripMenuItem_Click(object sender, EventArgs e)
    {
        Form2 f2 = new Form2();
        f2.MdiParent = this; // 设置当前窗体为父容器
        f2.Show();

        Form3 f3 = new Form3();
        f3.MdiParent = this;
        f3.BackColor = Color.Red;
        f3.Show();

        // 垂直平铺所有子窗体
        LayoutMdi(MdiLayout.TileVertical);
    }

    /// <summary>
    /// 设置子窗体为水平平铺
    /// </summary>
    private void 设置窗体ToolStripMenuItem_Click(object sender, EventArgs e)
    {
        LayoutMdi(MdiLayout.TileHorizontal);
    }

    /// <summary>
    /// 单实例打开子窗体:同类型窗体已存在则激活,否则隐藏其他类型并打开新的
    /// </summary>
    public void Open(Form f)
    {
        // 检查是否已存在同类型的子窗体
        foreach (var item in this.MdiChildren)
        {
            if (f.GetType() == item.GetType())
            {
                foreach (Form child in this.MdiChildren)
                {
                    child.Hide();
                }
                item.Show();
                item.Activate();
                return;
            }
        }

        // 隐藏所有现有子窗体,打开新窗体
        foreach (Form child in this.MdiChildren)
        {
            child.Hide();
        }
        f.MdiParent = this;
        f.Show();
    }
}

二、页面布局与布局控件

8.1 布局属性详解

属性 说明
Anchor 锚定属性,设置控件边缘相对于父容器的锚定状态,默认左上锚定
Dock 依靠属性,使控件停靠在父容器的某个边缘或填充整个容器
Padding 控件内部内容与边缘的距离
Margin 控件与周边其他控件的距离
AutoSize 是否自动适应内容大小
AutoSizeMode 自动适应大小的模式(仅增、又增又减等)

8.2 FlowLayoutPanel(流式布局)

控件按照指定方向(水平或垂直)自动排列,支持自动换行。

public Form1()
{
    InitializeComponent();

    // 动态创建 10 个按钮并加入流式布局面板
    for (int i = 0; i < 10; i++)
    {
        Button btn = new Button()
        {
            Text = "按钮",
        };
        // 设置按钮与周边控件的距离
        btn.Margin = new Padding(10, 10, 0, 0);
        this.flowLayoutPanel1.Controls.Add(btn);
    }
}

设计器关键属性:

  • FlowDirection:流动方向(LeftToRightTopDownRightToLeftBottomUp
  • WrapContents:是否自动换行(true / false

8.3 TableLayoutPanel(网格布局)

创建行列网格,控件可放置在指定单元格内,并随容器大小变化自动调整。

private void Form1_Load(object sender, EventArgs e)
{
    TableLayoutPanel tableLayoutPanel1 = new TableLayoutPanel();

    // 填充整个父容器
    tableLayoutPanel1.Dock = DockStyle.Fill;

    // 设置 4 列 3 行
    tableLayoutPanel1.ColumnCount = 4;
    tableLayoutPanel1.RowCount = 3;

    // 每列各占 25% 宽度
    tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 25F));
    tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 25F));
    tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 25F));
    tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 25F));

    // 每行各占 33.33% 高度
    tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Percent, 33.33F));
    tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Percent, 33.33F));
    tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Percent, 33.33F));

    this.Controls.Add(tableLayoutPanel1);

    // 向第 0 行第 0 列添加标签
    Label label1 = new Label
    {
        Text = "Label 1",
        Dock = DockStyle.Fill,
        TextAlign = ContentAlignment.MiddleCenter,
        BackColor = Color.Red
    };
    tableLayoutPanel1.Controls.Add(label1, 0, 0);

    // 向第 1 行第 1 列添加按钮
    Button button1 = new Button
    {
        Text = "Button 1",
        Dock = DockStyle.Fill
    };
    tableLayoutPanel1.Controls.Add(button1, 1, 1);
}

8.4 SplitContainer(分割容器)

将窗体分割为两个可调整大小的面板(Panel1Panel2),常用于资源管理器式布局。

// 设计器生成的典型配置
this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill;
this.splitContainer1.SplitterDistance = 260; // 分隔条初始位置

// 在 Panel2 中添加 TabControl
this.splitContainer1.Panel2.Controls.Add(this.tabControl1);

8.5 TabControl(分页控件)

将多个页面内容组织到选项卡中,节省界面空间。

// 关键设计器属性
this.tabControl1.SelectedIndex = 0; // 默认显示第一个选项卡

// 各页面(TabPage)可独立放置控件
this.tabPage1.Controls.Add(this.richTextBox1);
this.tabPage2.Controls.Add(this.pictureBox1);
this.tabPage3.Controls.Add(this.button1);

九、实用技巧与注意事项

9.1 使用 Tag 属性存储自定义数据

WinForms 控件的 Tag 属性类型为 object,非常适合临时存储与控件关联的自定义对象,避免额外的字典映射。

ListViewItem item = new ListViewItem("文件名");
item.Tag = new FileMessage { Name = "test.txt", Size = 1024 };
// 后续通过 item.Tag 取出数据

9.2 动态创建控件

Button btn = new Button()
{
    Text = "动态按钮",
    Location = new Point(10, 10),
    Size = new Size(100, 30)
};
btn.Click += (sender, e) => { MessageBox.Show("点击了动态按钮"); };
this.Controls.Add(btn);

9.3 文件属性判断

if (item.Attributes.HasFlag(FileAttributes.Hidden))
{
    continue; // 跳过隐藏文件或目录
}

9.4 窗体显示模式

// 模式对话框:阻塞父窗体,必须关闭后才能操作父窗体
form.ShowDialog();

// 非模式窗口:不阻塞,可并行操作
form.Show();

9.5 自动滚动设置

tableLayoutPanel1.AutoScroll = true;
tableLayoutPanel1.AutoScrollMargin = new Size(20, 20); // 滚动条额外边距

更多推荐