MDI 多文档界面容器窗体

MDI 多文档界面容器窗体

MDI(Multiple Document Interface,多文档界面)允许在一个主窗体中容纳多个子窗体,类似 Excel、Word 的多文档工作方式。

基本设置

1. 将主窗体设为 MDI 容器

在窗体属性中将 IsMdiContainer 设为 true,窗体背景会自动变为深色(MDI 工作区)。

2. 子窗体指定父容器

private void button1_Click(object sender, EventArgs e)
{
    FormAddUser fa = new FormAddUser("foxdevelop.com");
    fa.MdiParent = this;              // 指定 MDI 父窗体
    fa.Show();                        // MDI 子窗体不能用 ShowDialog()
}Code language: JavaScript (javascript)

MDI 子窗体必须使用 Show(),不能使用 ShowDialog(),否则会抛异常。

子窗体最小化行为

MDI 子窗体被最小化后,会自动收拢到主窗体底部形成一个排列条(类似 Windows 任务栏),点击即可还原。这是 MDI 的默认行为,无需额外编码。

常用属性

属性说明
IsMdiContainer主窗体是否作为 MDI 容器
MdiChildren获取所有已打开的 MDI 子窗体数组
MdiParent子窗体指定其父 MDI 窗体
ActiveMdiChild获取当前活动(焦点)的子窗体
this.IsMdiContainer = true;                              // 设为 MDI 容器

FormAddUser child = new FormAddUser();
child.MdiParent = this;
child.Show();

// 获取当前活动的子窗体
if (this.ActiveMdiChild != null)
{
    this.ActiveMdiChild.Text = "活动子窗体";
}

// 遍历所有子窗体
foreach (Form childForm in this.MdiChildren)
{
    childForm.Close();
}Code language: JavaScript (javascript)

排列子窗体

MDI 支持多种子窗体排列方式:

// 层叠排列
this.LayoutMdi(MdiLayout.Cascade);

// 水平平铺
this.LayoutMdi(MdiLayout.TileHorizontal);

// 垂直平铺
this.LayoutMdi(MdiLayout.TileVertical);

// 排列最小化按钮(底部排列条)
this.LayoutMdi(MdiLayout.ArrangeIcons);Code language: JavaScript (javascript)

通常在菜单或工具栏中提供排列选项:

private void 层叠ToolStripMenuItem_Click(object sender, EventArgs e)
{
    this.LayoutMdi(MdiLayout.Cascade);
}

private void 水平平铺ToolStripMenuItem_Click(object sender, EventArgs e)
{
    this.LayoutMdi(MdiLayout.TileHorizontal);
}

private void 垂直平铺ToolStripMenuItem_Click(object sender, EventArgs e)
{
    this.LayoutMdi(MdiLayout.TileVertical);
}Code language: JavaScript (javascript)

防止重复打开同一子窗体

private void OpenChildForm<T>() where T : Form, new()
{
    // 检查是否已打开
    foreach (Form child in this.MdiChildren)
    {
        if (child.GetType() == typeof(T))
        {
            child.Activate();   // 已打开则激活
            return;
        }
    }

    // 未打开则新建
    T newChild = new T();
    newChild.MdiParent = this;
    newChild.Show();
}

// 调用
private void button1_Click(object sender, EventArgs e)
{
    OpenChildForm<FormAddUser>();
}Code language: JavaScript (javascript)

与事件回调配合

MDI 子窗体同样可以使用事件通知父窗体:

private void button1_Click(object sender, EventArgs e)
{
    FormAddUser fa = new FormAddUser("foxdevelop.com");
    fa.MdiParent = this;
    fa.refleshEvent += Fa_refleshEvent;  // 订阅子窗体事件
    fa.Show();
}

private void Fa_refleshEvent(string username)
{
    this.Text = username;
    // 刷新主窗体中的数据列表
}Code language: JavaScript (javascript)

MDI 菜单合并

如果子窗体也有 MenuStrip,打开后会自动与父窗体的菜单合并:

属性说明
AllowMerge是否允许菜单合并(默认 true)
MergeAction合并方式(Append、Insert、Replace、Remove、MatchOnly)
MergeIndex合并位置索引
// 子窗体菜单项设置
this.子窗体菜单ToolStripMenuItem.MergeAction = MergeAction.Insert;
this.子窗体菜单ToolStripMenuItem.MergeIndex = 1;Code language: JavaScript (javascript)

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注