有没有一种方法可以显示“阻塞”?WinForms快捷菜单

本文关键字:阻塞 WinForms 菜单 显示 一种 方法 有没有 | 更新日期: 2023-09-27 18:16:52

是否有一种方法可以显示ContextMenu并阻止进一步执行,直到项目被选中?特别是,我想获得类似于ShowDialog()的行为,但对于ContextMenu

直接的方法不起作用:

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

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

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

这似乎有效,但感觉"不干净":

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

有更好的方法吗?

有没有一种方法可以显示“阻塞”?WinForms快捷菜单

抱歉第一个答案。这是我尝试过的。我制作了另一个表单,在其中放置了上下文菜单和计时器。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();
    }
}

你可以很容易地防止垃圾收集的上下文菜单,而它仍然是显示。

问题是您正在使用lambda作为菜单项的事件处理程序。这是一个匿名方法,因此本身不附加到任何对象实例,这将导致上下文菜单被引用,因此保持活跃。向封闭对象添加一个方法,然后创建一个标准的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();