我希望在单击菜单项时显示包含“删除”,“重命名”等项的上下文菜单。
右键单击菜单项时如何绑定上下文菜单?
最佳答案
我想到的第一个想法是在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
。