在開發 MDI (Multiple Document Interface) 應用程式時,常遇到一個需求:同一類型的子視窗在主視窗中只能開啟一個實例。若使用者再次嘗試開啟相同功能視窗,應直接啟動既有實例而非建立新視窗。這篇文章分享一個利用 C# 泛型實作的通用解決方案。
每個 MDI 子視窗本質上都是繼承自 Form 類別,不同功能對應不同子類別。因此,只需遍歷主視窗的 MdiChildren 集合,檢查是否已存在目標型別的實例即可。若存在則呼叫 Activate() 將其帶到最前;若不存在則實例化新視窗、設定 MdiParent 並顯示。
以下程式碼展示一個可重複使用的泛型方法 OpenUniqueMDIChildWindow<T>,約束 T 必須為 Form 且具無參數建構函式:
/// <summary>
/// 開啟 MDI 子視窗並附加至主視窗,若同類型視窗已存在則直接啟動
/// </summary>
/// <typeparam name="T">MDI 子視窗型別</typeparam>
/// <param name="mdiParent">MDI 主視窗參考</param>
/// <returns>目前建立或取得的子視窗實例參考</returns>
private T OpenUniqueMDIChildWindow<T>(Form mdiParent) where T : Form, new()
{
foreach (Form subForm in mdiParent.MdiChildren)
{
if (subForm.GetType().Equals(typeof(T)))
{
subForm.Activate();
return subForm as T;
}
}
T newForm = new T();
newForm.MdiParent = mdiParent;
newForm.Show();
return newForm;
}
在主視窗的選單項目或工具列按鈕點擊事件中,即可輕鬆呼叫:
// 開啟或啟動「客戶管理」視窗
OpenUniqueMDIChildWindow<CustomerManagementForm>(this);
// 開啟或啟動「庫存查詢」視窗
OpenUniqueMDIChildWindow<InventoryQueryForm>(this);
if-else 或 switch 判斷邏輯。此模式同樣適用於 WPF 的 Window 或其他視窗框架,只需調整型別約束與啟動 API 即可。掌握這個技巧,能讓 MDI 應用程式的視窗管理更加優雅且健壯。