2

我希望当我单击一个菜单项时,显示一个上下文菜单,其中包含“删除”、“重命名”等项目。

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

4

1 回答 1

2

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

在此处输入图像描述

于 2013-11-15T15:22:19.920 回答