有没有办法显示“阻止”WinForms ContextMenu?

有没有办法显示ContextMenu并阻止进一步执行,直到选择了一个项目? 特别是,我希望获得类似于ShowDialog()行为,但是对于ContextMenu

直接的方法不起作用:

 ContextMenu cm = new ContextMenu(); cm.MenuItems.Add("1", (s,e) => {value = 1;}); cm.Show(control, location); 

因为Click回调不是直接从Show()调用,而是在消息循环处理click事件时稍后调用。

如果你运气不好, menu会在事件处理之前被垃圾收集,在这种情况下,事件就会无声地丢失。 (这意味着你不能以这种方式真正使用ContextMenu的局部变量。)

这似乎有效,但感觉“不洁”:

 using (ContextMenu cm = new ContextMenu()) { cm.MenuItems.Add("1", (s,e) => {value = 1;}); cm.Show(control, location); Application.DoEvents(); } 

有没有更好的办法?

对不起第一个答案。 这是我尝试过的。 我创建了另一个表单,我将上下文菜单和一个timer.Form2显示为Form1的模态,然后计时器显示Form2上的上下文菜单。

请注意,表单2有一些属性设置:在任务栏中不可见,没有边框,大小应该与上下文菜单的大小相等。

希望这可以帮助。

 public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void Form1_MouseUp(object sender, MouseEventArgs e) { if (e.Button == MouseButtons.Right) { Form2 ctxForm = new Form2(); ctxForm.Location = this.PointToScreen(e.Location); ctxForm.Size = new Size(0, 0); ctxForm.ShowDialog(); } } } public partial class Form2 : Form { public Form2() { InitializeComponent(); } private void exitToolStripMenuItem_Click(object sender, EventArgs e) { this.Close(); } private void timer1_Tick(object sender, EventArgs e) { //show menu once contextMenuStrip1.Show(this, PointToClient(Location)); contextMenuStrip1.Focus(); timer1.Enabled = false; } private void contextMenuStrip1_Closed(object sender, ToolStripDropDownClosedEventArgs e) { this.Close(); } } 

您可以轻松地阻止ContextMenu的垃圾收集,同时仍然显示它。

问题是您使用lambda作为菜单项的事件处理程序。 这是一个匿名方法,因此它本身不附加到任何会导致ContextMenu被引用并因此保持活动的对象实例。 将方法添加到封闭对象,然后创建标准EventHandler。 这样,封闭实例的存在将使ContextMenu保持活动状态。 不是简洁和非常C#1.0,​​但它将解决问题。

只是等待菜单不可见。

 ContextMenu cm = new ContextMenu(); cm.MenuItems.Add("1", (s,e) => {value = 1;}); cm.Show(control, location); while (cm.Visible == true) Application.DoEvents();