有没有办法显示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();
}
有更好的方法吗?
答案 0 :(得分:1)
对不起第一个答案。这是我尝试过的。我创建了另一个表单,我将上下文菜单和一个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();
}
}
答案 1 :(得分:0)
您可以轻松地阻止ContextMenu的垃圾收集,同时仍然显示它。
问题是您使用lambda作为菜单项的事件处理程序。这是个 匿名方法,因此不会附加到任何会导致ContextMenu被引用并保持活动的对象实例。将方法添加到封闭对象,然后创建标准EventHandler。这样,封闭实例的存在将使ContextMenu保持活动状态。不是简洁而且非常C#1.0,但它会解决问题。
答案 2 :(得分:0)
等待菜单不可见。
ContextMenu cm = new ContextMenu();
cm.MenuItems.Add("1", (s,e) => {value = 1;});
cm.Show(control, location);
while (cm.Visible == true) Application.DoEvents();