C# 右键单击菜单项时如何显示上下文菜单
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/281831/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to show a Context Menu when you right click a Menu Item
提问by Rob Prouse
I am porting an MFC application to .NET WinForms. In the MFC application, you can right click on a menu or on a context menu item and we show another context menu with diagnostic and configuration items. I am trying to port this functionality to .NET, but I am having trouble.
我正在将 MFC 应用程序移植到 .NET WinForms。在 MFC 应用程序中,您可以右键单击菜单或上下文菜单项,我们会显示另一个带有诊断和配置项的上下文菜单。我正在尝试将此功能移植到 .NET,但遇到了问题。
I have been able to capture the right click, disable the click of the underlying menu and pop up a context menu at the right location, but the original menu disappears as soon as it loses focus.
我已经能够捕获右键单击,禁用底层菜单的单击并在正确的位置弹出上下文菜单,但是原始菜单一旦失去焦点就会消失。
In MFC, we show the new context menu by calling TrackPopupMenuExwith the TPM_RECURSEflag.
在 MFC 中,我们通过调用带有TPM_RECURSE标志的TrackPopupMenuEx 来显示新的上下文菜单。
ContextMenuand the newer ContextMenuStripclasses in .NET only have a Showmethod. Does anyone know how to do this in .NET?
.NET 中的ContextMenu和较新的ContextMenuStrip类只有一个Show方法。有谁知道如何在 .NET 中做到这一点?
EDIT
编辑
I have tried using TrackPopupMenuExthrough a p/invoke, but that limits you to using a ContextMenu instead of a ContextMenuStrip which looks out of place in our application. It also still does not work correctly. It doesn't work with the new MenuStripand ContextMenuStrip.
我曾尝试通过 ap/invoke使用TrackPopupMenuEx,但这限制了您只能使用 ContextMenu 而不是 ContextMenuStrip,这在我们的应用程序中显得格格不入。它也仍然无法正常工作。它不适用于新的MenuStrip和ContextMenuStrip。
I have also tried subclassing ToolStripMenuItem to see if I can add a context menu to it. That is working for MenuStrip, but ContextMenuStripstill allows the right click events to pass through as clicks.
我还尝试对 ToolStripMenuItem 进行子类化,以查看是否可以向其添加上下文菜单。这适用于MenuStrip,但ContextMenuStrip仍然允许右键单击事件作为点击通过。
采纳答案by Eren Aygunes
Edit, due to a comment:
编辑,由于评论:
In:
在:
protected override void OnClick(EventArgs e)
{
if (SecondaryContextMenu == null || MouseButtons != MouseButtons.Right)
{
base.OnClick(e);
}
}
this part
这部分
MouseButtons != MouseButtons.Right
should and does compile as it is a call to Control.MouseButtons. Since the Form inherits Control class, it is sufficient to call MouseButtons property directly.
应该并且确实编译,因为它是对 Control.MouseButtons 的调用。由于 Form 继承了 Control 类,因此直接调用 MouseButtons 属性就足够了。
Hope this helps:
希望这可以帮助:
public partial class Form1 : Form
{
class CustomToolStripMenuItem : ToolStripMenuItem
{
private ContextMenuStrip secondaryContextMenu;
public ContextMenuStrip SecondaryContextMenu
{
get
{
return secondaryContextMenu;
}
set
{
secondaryContextMenu = value;
}
}
public CustomToolStripMenuItem(string text)
: base(text)
{ }
protected override void Dispose(bool disposing)
{
if (disposing)
{
if (secondaryContextMenu != null)
{
secondaryContextMenu.Dispose();
secondaryContextMenu = null;
}
}
base.Dispose(disposing);
}
protected override void OnClick(EventArgs e)
{
if (SecondaryContextMenu == null || MouseButtons != MouseButtons.Right)
{
base.OnClick(e);
}
}
}
class CustomContextMenuStrip : ContextMenuStrip
{
private bool secondaryContextMenuActive = false;
private ContextMenuStrip lastShownSecondaryContextMenu = null;
protected override void Dispose(bool disposing)
{
if (disposing)
{
if (lastShownSecondaryContextMenu != null)
{
lastShownSecondaryContextMenu.Close();
lastShownSecondaryContextMenu = null;
}
}
base.Dispose(disposing);
}
protected override void OnControlAdded(ControlEventArgs e)
{
e.Control.MouseClick += new MouseEventHandler(Control_MouseClick);
base.OnControlAdded(e);
}
protected override void OnControlRemoved(ControlEventArgs e)
{
e.Control.MouseClick -= new MouseEventHandler(Control_MouseClick);
base.OnControlRemoved(e);
}
private void Control_MouseClick(object sender, MouseEventArgs e)
{
ShowSecondaryContextMenu(e);
}
protected override void OnMouseClick(MouseEventArgs e)
{
ShowSecondaryContextMenu(e);
base.OnMouseClick(e);
}
private bool ShowSecondaryContextMenu(MouseEventArgs e)
{
CustomToolStripMenuItem ctsm = this.GetItemAt(e.Location) as CustomToolStripMenuItem;
if (ctsm == null || ctsm.SecondaryContextMenu == null || e.Button != MouseButtons.Right)
{
return false;
}
lastShownSecondaryContextMenu = ctsm.SecondaryContextMenu;
secondaryContextMenuActive = true;
ctsm.SecondaryContextMenu.Closed += new ToolStripDropDownClosedEventHandler(SecondaryContextMenu_Closed);
ctsm.SecondaryContextMenu.Show(Cursor.Position);
return true;
}
void SecondaryContextMenu_Closed(object sender, ToolStripDropDownClosedEventArgs e)
{
((ContextMenuStrip)sender).Closed -= new ToolStripDropDownClosedEventHandler(SecondaryContextMenu_Closed);
lastShownSecondaryContextMenu = null;
secondaryContextMenuActive = false;
Focus();
}
protected override void OnClosing(ToolStripDropDownClosingEventArgs e)
{
if (secondaryContextMenuActive)
{
e.Cancel = true;
}
base.OnClosing(e);
}
}
public Form1()
{
InitializeComponent();
CustomToolStripMenuItem itemPrimary1 = new CustomToolStripMenuItem("item primary 1");
itemPrimary1.SecondaryContextMenu = new ContextMenuStrip();
itemPrimary1.SecondaryContextMenu.Items.AddRange(new ToolStripMenuItem[] {
new ToolStripMenuItem("item primary 1.1"),
new ToolStripMenuItem("item primary 1.2"),
});
CustomToolStripMenuItem itemPrimary2 = new CustomToolStripMenuItem("item primary 2");
itemPrimary2.DropDownItems.Add("item primary 2, sub 1");
itemPrimary2.DropDownItems.Add("item primary 2, sub 2");
itemPrimary2.SecondaryContextMenu = new ContextMenuStrip();
itemPrimary2.SecondaryContextMenu.Items.AddRange(new ToolStripMenuItem[] {
new ToolStripMenuItem("item primary 2.1"),
new ToolStripMenuItem("item primary 2.2"),
});
CustomContextMenuStrip primaryContextMenu = new CustomContextMenuStrip();
primaryContextMenu.Items.AddRange(new ToolStripItem[]{
itemPrimary1,
itemPrimary2
});
this.ContextMenuStrip = primaryContextMenu;
}
}
回答by Jason Diller
You'll probably have to p/invoke the method.
您可能必须调用/调用该方法。
[DllImport("user32.dll")]
static extern bool TrackPopupMenuEx(IntPtr hmenu, uint fuFlags, int x, int y,
IntPtr hwnd, IntPtr lptpm);
const int TPM_RECURSE = 0x0001;
回答by Eren Aygunes
This shows how to use multiple ContextMenus as well as different ones with any combination of mouse clicks.
这显示了如何使用多个 ContextMenu 以及通过任意鼠标单击组合使用不同的 ContextMenu。
More here: http://code.msdn.microsoft.com/TheNotifyIconExample