讓多個控制項共享單一 ContextMenu,並在 Popup 事件中動態調整選單項目,可減少元件數量、簡化維護。本文完整實作 CheckBox (三態) 與 RadioButton 共享選單的範例。
checkBox1:ThreeState = true,ContextMenu = contextMenu1radioButton1:ContextMenu = contextMenu1contextMenu1:共享選單元件
private void contextMenu1_Popup(object sender, EventArgs e)
{
// 1. 清除現有選單項
contextMenu1.MenuItems.Clear();
// 2. 基本項目:所有控制項通用
contextMenu1.MenuItems.Add("選取 (&C)", new EventHandler(Checked_OnClick));
contextMenu1.MenuItems.Add("取消選取 (&U)", new EventHandler(Unchecked_OnClick));
// 3. 針對 CheckBox 動態加入「不確定」項目
if (contextMenu1.SourceControl == checkBox1)
{
contextMenu1.MenuItems.Add("不確定 (&I)", new EventHandler(Indeterminate_OnClick));
}
}
private void Checked_OnClick(object sender, EventArgs e)
{
// 根據來源控制項類型執行對應動作
if (contextMenu1.SourceControl == radioButton1)
{
radioButton1.Checked = true;
}
else if (contextMenu1.SourceControl == checkBox1)
{
checkBox1.Checked = true;
}
}
private void Unchecked_OnClick(object sender, EventArgs e)
{
if (contextMenu1.SourceControl == radioButton1)
{
radioButton1.Checked = false;
}
else if (contextMenu1.SourceControl == checkBox1)
{
checkBox1.Checked = false;
}
}
private void Indeterminate_OnClick(object sender, EventArgs e)
{
if (contextMenu1.SourceControl == checkBox1)
{
checkBox1.CheckState = CheckState.Indeterminate;
}
}
ContextMenu.SourceControl 回傳觸發選單的控制項參考,是動態選單的核心識別依據。
public partial class DynamicContextMenuForm : Form
{
public DynamicContextMenuForm()
{
InitializeComponent();
// 設計器自動產生的關鍵設定:
// checkBox1.ThreeState = true;
// checkBox1.ContextMenu = contextMenu1;
// radioButton1.ContextMenu = contextMenu1;
// contextMenu1.Popup += contextMenu1_Popup;
}
private void contextMenu1_Popup(object sender, EventArgs e) { ... }
private void Checked_OnClick(object sender, EventArgs e) { ... }
private void Unchecked_OnClick(object sender, EventArgs e) { ... }
private void Indeterminate_OnClick(object sender, EventArgs e) { ... }
}
private void contextMenu1_Popup(object sender, EventArgs e)
{
contextMenu1.MenuItems.Clear();
Control source = contextMenu1.SourceControl;
// 通用項目
contextMenu1.MenuItems.Add("複製 (&C)", (s, e) => DoCopy(source));
contextMenu1.MenuItems.Add("貼上 (&P)", (s, e) => DoPaste(source));
contextMenu1.MenuItems.Add(new MenuItem("-")); // 分隔線
// 型別專屬項目
switch (source)
{
case TextBox txt:
contextMenu1.MenuItems.Add("清空 (&L)", (s, e) => txt.Clear());
contextMenu1.MenuItems.Add("全選 (&A)", (s, e) => txt.SelectAll());
break;
case ListBox lb:
contextMenu1.MenuItems.Add("移除選取 (&R)", (s, e) => RemoveSelected(lb));
contextMenu1.MenuItems.Add("排序 (&S)", (s, e) => lb.Sorted = !lb.Sorted);
break;
case DataGridView dgv:
contextMenu1.MenuItems.Add("匯出 Excel (&E)", (s, e) => ExportToExcel(dgv));
break;
}
contextMenu1.MenuItems.Add(new MenuItem("-"));
contextMenu1.MenuItems.Add("屬性 (&R)", (s, e) => ShowProperties(source));
}
| 原則 | 說明 |
|---|---|
| 共享選單 | 相似功能控制項共用一個 ContextMenu 元件 |
| Popup 事件建構 | 每次顯示前動態建構,確保狀態最新 |
| SourceControl 識別 | 以此屬性判斷來源控制項,執行對應邏輯 |
| MenuItems.Clear() | 每次 Popup 開頭清除,避免項目重複累積 |
| 事件處理器複用 | 通用動作 (複製/貼上) 共用處理器,型別專屬動作分開 |
ContextMenu 為 .NET Framework 1.0 版本,新專案建議使用 ContextMenuStrip (功能更豐富、渲染更現代)MenuItem.MenuItems動態 ContextMenu 透過 Popup 事件 + SourceControl 識別 + MenuItems.Clear/Add 重建,實現多控制項共享單一選單元件且呈現差異化選項。此模式減少元件數量、集中邏輯、易於維護擴充。