有没有办法显示"阻止" WinForms ContextMenu?

时间:2011-12-06 16:03:48

标签: c# .net winforms garbage-collection 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();
}

有更好的方法吗?

3 个答案:

答案 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();