Multiple Document Interface (MDI) 允許單一主視窗容納多個子視窗,經典應用如舊版 Word/Excel、Visual Studio 6.0。WinForms 透過 `Form.IsMdiContainer` 與 `Form.MdiParent` 輕鬆實現。本文展示完整建立流程、子視窗管理、常見問題與現代 UI 架構替代建議。
public partial class MdiMainForm : Form
{
public MdiMainForm()
{
InitializeComponent();
IsMdiContainer = true; // 關鍵:標記為 MDI 容器
// 選配:背景圖片、滾動條自動
// this.BackgroundImage = Properties.Resources.MdiBackground;
}
// 選單項建立子視窗
private void 新增視窗ToolStripMenuItem_Click(object sender, EventArgs e)
{
var child = new MdiChildForm();
child.MdiParent = this; // 關鍵:指定父容器
child.Text = $"文件 {MdiChildren.Length + 1}";
child.Show();
}
// 佈局選單
private void 瀑布式ToolStripMenuItem_Click(object sender, EventArgs e) => LayoutMdi(MdiLayout.Cascade);
private void 水平平鋪ToolStripMenuItem_Click(object sender, EventArgs e) => LayoutMdi(MdiLayout.TileHorizontal);
private void 垂直平鋪ToolStripMenuItem_Click(object sender, EventArgs e) => LayoutMdi(MdiLayout.TileVertical);
private void 排列圖示ToolStripMenuItem_Click(object sender, EventArgs e) => LayoutMdi(MdiLayout.ArrangeIcons);
// 關閉所有子視窗
private void 關閉全部ToolStripMenuItem_Click(object sender, EventArgs e)
{
foreach (Form child in MdiChildren) child.Close();
}
}
public partial class MdiChildForm : Form
{
public MdiChildForm()
{
InitializeComponent();
// 子視窗常用設定
// this.WindowState = FormWindowState.Maximized; // 預設最大化
}
// 子視窗關閉按鈕
private void btnClose_Click(object sender, EventArgs e) => Close();
}
private void OpenChildForm() where T : Form, new()
{
// 查找現有實例
foreach (Form child in MdiChildren)
{
if (child.GetType() == typeof(T))
{
child.Activate(); // 置頂聚焦
if (child.WindowState == FormWindowState.Minimized)
child.WindowState = FormWindowState.Normal;
return;
}
}
// 不存在則建立新實例
var newChild = new T { MdiParent = this };
newChild.Show();
}
// 使用
private void 客戶管理ToolStripMenuItem_Click(object sender, EventArgs e) => OpenChildForm();
private void 訂單管理ToolStripMenuItem_Click(object sender, EventArgs e) => OpenChildForm();
| 問題 | 原因 | 解決 |
|---|---|---|
| 子視窗標題列雙重顯示 | MDI 容器會在自己的標題列附加子視窗標題 | 主視窗 `Text` 設為空或簡短;子視窗 `Text` 含完整標題 |
| 選單合併異常 | 子視窗選單自動合併到主視窗 | 子視窗 `MainMenuStrip` 設為 null,或手動管理 `MergeMenu` |
| 滾動條不出現 | 子視窗超出客戶區 | 主視窗 `AutoScroll = true` (僅當非最大化時) |
| 高 DPI 模糊/縮放錯誤 | MDI 在高 DPI 下渲染問題多 | 專案啟用 Per-Monitor DPI V2,或避免使用 MDI |
| 子視窗無法置頂於非 MDI 視窗 | MDI 子視窗 Z-order 受限於容器 | 改用非 MDI 浮動視窗架構 |
WinForms MDI 實現極簡單:`IsMdiContainer=true` + `MdiParent=this` + `Show()`。核心優勢是視窗管理內建 (佈局、列表、啟用)。但**高 DPI、現代 UX、跨平台**皆為弱項。新開發請優先選擇 **Tabbed Interface (DockPanel Suite)** 或 **單視窗導航架構**,獲得一致、可擴展、高 DPI 友善的使用者體驗。