我希望在单击菜单项时显示包含“删除”,“重命名”等项的上下文菜单。

右键单击菜单项时如何绑定上下文菜单?

最佳答案

我想到的第一个想法是在MouseDown上关联一些ToolStripMenuItem事件,并在屏幕坐标中的鼠标位置显示第二个ContextMenuStrip。但这不是那么简单。问题在于这样做将需要为每个项目连接事件,在该事件上以某种方式显示第二个ContextMenuStrip将关闭当前的ContextMenuStrip(即使我们添加了一些Closing事件处理程序并设置了e.Cancel = true;)。这里有点棘手。我们可以想到当前MouseDownContextMenuStrip事件,但实际上几乎不会触发此事件,因为所有项目都位于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的项目,可以访问SourceItemNativeContextMenuStrip

10-08 09:36