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)
Previous: 子窗体操作完成后通知父窗体刷新