Как добавить ContextMenuStrip в ToolStripMenuItem

Я хочу, чтобы при нажатии на элемент меню отображалось контекстное меню с такими элементами, как "удалить", "переименовать" и т.д.

Как связать себя контекстным меню, когда вы щелкаете правой кнопкой мыши по элементу меню?

1 ответ

Первая идея, прыгнувшая в моем сознании, - подключить какое- MouseDown событие MouseDown на ToolStripMenuItem и показать второй ContextMenuStrip в позиции мыши в координатах экрана. Но это не так просто. Проблема в том, что это потребует подключения события для каждого элемента, в этом случае каким-то образом показано, что второй ContextMenuStrip закроет текущий ContextMenuStrip (даже мы добавим некоторый обработчик событий Closing и установим e.Cancel = true;). Здесь немного сложно. Мы могли бы подумать о событии MouseDown текущего ContextMenuStrip но на самом деле это событие вряд ли запущено, потому что все элементы лежат поверх ContextMenuStrip. Это заставило меня задуматься о более глубокой стадии, когда мы можем поймать WM_RBUTTONDOWN и запустить там код. Мы можем настроить ContextMenuStrip чтобы поймать это сообщение в WndProc или использовать пользовательский NativeWindow. Я хотел бы использовать NativeWindow здесь. Это время для кода (отлично работает):

public class NativeContextMenuStrip : NativeWindow
{
 public class ShowContextMenuEventArgs : EventArgs {
 public ToolStripDropDown ContextMenuToShow {get; set;}
 }
 public delegate void ShowContextMenuEventHandler(ShowContextMenuEventArgs e);
 public event ShowContextMenuEventHandler ShowContextMenu;
 private Color previousItemBackColor;
 public ToolStripItem SourceItem { get; set; }
 bool keepOpen;
 protected override void WndProc(ref Message m)
 { 
 base.WndProc(ref m); 
 if (m.Msg == 0x204) {//WM_RBUTTONDOWN
 OnShowContextMenu(new ShowContextMenuEventArgs());
 }
 }
 protected virtual void OnShowContextMenu(ShowContextMenuEventArgs e)
 {
 var handler = ShowContextMenu;
 if (handler != null)
 {
 handler(e);
 if (e.ContextMenuToShow != null)
 {
 ContextMenuStrip toolStrip = (ContextMenuStrip)Control.FromHandle(Handle);
 Point client = toolStrip.PointToClient(Control.MousePosition);
 SourceItem = toolStrip.GetItemAt(client);
 previousItemBackColor = SourceItem.BackColor;
 SourceItem.BackColor = SystemColors.MenuHighlight; 
 e.ContextMenuToShow.Closed -= restoreItemState;
 e.ContextMenuToShow.Closed += restoreItemState;
 keepOpen = true;
 e.ContextMenuToShow.Show(Control.MousePosition);
 keepOpen = false;
 }
 } 
 }
 protected override void OnHandleChange()
 {
 base.OnHandleChange();
 ContextMenuStrip toolStrip = Control.FromHandle(Handle) as ContextMenuStrip;
 if (toolStrip != null)
 {
 toolStrip.Closing += toolStripClosing;
 }
 }
 private void restoreItemState(object sender, EventArgs e)
 {
 SourceItem.BackColor = previousItemBackColor;
 SourceItem.Owner.Show();
 }
 private void toolStripClosing(object sender, ToolStripDropDownClosingEventArgs e)
 {
 e.Cancel = keepOpen;
 }
}

Использование:: Важным событием является ShowContextMenu, подключить это событие и установить ContextMenuStrip вы хотите показать. Все это. Вот деталь:

public partial class Form1 : Form {
 public Form1(){
 InitializeComponent();
 //suppose you have a main ContextMenuStrip and a sub ContextMenuStrip
 //try adding some items for both
 ContextMenuStrip = new ContextMenuStrip();
 ContextMenuStrip.Items.Add("Item 1");
 ContextMenuStrip.Items.Add("Item 2");
 //sub ContextMenuStrip
 var subMenu = new ContextMenuStrip();
 subMenu.Items.Add("Delete");
 subMenu.Items.Add("Rename"); 
 ContextMenuStrip.HandleCreated += (s,e) => {
 nativeMenu.AssignHandle(ContextMenuStrip.Handle);
 nativeMenu.ShowContextMenu += (ev) => {
 ev.ContextMenuToShow = subMenu;
 };
 };
 }
 NativeContextMenuStrip nativeMenu = new NativeContextMenuStrip();
}

Для того, чтобы получить пункт, нажав на который показывает суб ContextMenuStrip, вы можете получить доступ к SourceItem в NativeContextMenuStrip.

licensed under cc by-sa 3.0 with attribution.