public partial class MdiMain : Form
{
private int _childCount = 0;
public MdiMain() => InitializeComponent();
private void mnuNewWindow_Click(object sender, EventArgs e)
{
_childCount++;
var child = new MdiChild
{
MdiParent = this,
Text = $"子視窗 {_childCount}"
};
child.Show(); // 非模態顯示
}
// 選單:平鋪/層疊/最小化所有
private void mnuTileHorizontal_Click(object sender, EventArgs e) => LayoutMdi(MdiLayout.TileHorizontal);
private void mnuTileVertical_Click(object sender, EventArgs e) => LayoutMdi(MdiLayout.TileVertical);
private void mnuCascade_Click(object sender, EventArgs e) => LayoutMdi(MdiLayout.Cascade);
private void mnuArrangeIcons_Click(object sender, EventArgs e) => LayoutMdi(MdiLayout.ArrangeIcons);
}
private void mnuOpenReport_Click(object sender, EventArgs e)
{
// 檢查是否已開啟同類型
var existing = MdiChildren.FirstOrDefault(f => f.GetType() == typeof(ReportForm));
if (existing != null)
{
existing.Activate(); // 置頂聚焦
return;
}
var report = new ReportForm { MdiParent = this };
report.FormClosed += (s, e) => { /* 可清理資源 */ };
report.Show();
}
public partial class MdiChild : Form
{
public MdiChild() => InitializeComponent();
private void btnClose_Click(object sender, EventArgs e) => Close();
protected override void OnFormClosed(FormClosedEventArgs e)
{
// 釋放非託管資源、取消訂閱事件等
base.OnFormClosed(e);
}
}
| 需求 | 解決方案 |
|---|---|
| 子視窗狀態持久化 | 覆寫 `OnClosing` 儲存 `Location`/`Size`/`WindowState` 至設定檔 |
| 父視窗選單動態合併 | 子視窗 `MenuStrip` 設定 `MergeAction` / `MergeIndex`,父視窗自動合併 |
| 工具列共用 | 父視窗 `ToolStrip` 可被子視窗透過 `MdiParent.Controls` 存取 |
| 跨子視窗通訊 | 父視窗做中介者 (Mediator) 或使用事件總線 |
| 自訂標籤頁式 MDI | 使用第三方套件 (DockPanel Suite, DevExpress, Telerik) 或自繪 `TabControl` 宿主 |
傳統 MDI 在高 DPI、觸控、跨平台支援較弱。新專案建議考慮:
MDI 是 WinForms 經典多文件介面架構,核心在於 `IsMdiContainer`、`MdiParent`、`LayoutMdi` 三大支柱。掌握單例開啟、選單合併、狀態持久化等實務技巧,即可快速建構傳統桌面企業應用。新專案請評估現代替代方案以獲得更佳使用者體驗。