Есть ли способ показать «блокирующий» WinForms ContextMenu? - PullRequest
4 голосов
/ 06 декабря 2011

Есть ли способ показать ContextMenu и заблокировать дальнейшее выполнение, пока элемент не будет выбран? В частности, я хочу получить поведение, подобное ShowDialog(), но для ContextMenu.

Прямой подход не работает:

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

, поскольку обратный вызов Click вызывается не напрямую из Show(), а в более поздний момент, когда цикл обработки сообщений обрабатывает событие click.

Если вам не повезло, menu - это сборщик мусора перед обработкой события, и в этом случае событие просто молча теряется. (Это означает, что вы не можете использовать локальные переменные для ContextMenu s таким образом.)

Кажется, это работает, но кажется "нечистым":

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

Есть ли лучший способ?

Ответы [ 3 ]

1 голос
/ 07 декабря 2011

Извините за первый ответ. Вот что я попробовал. Я сделал другую Форму, где я помещаю контекстное меню, и 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();
    }
}
0 голосов
/ 08 декабря 2013

Просто подождите, пока меню не станет видимым.

ContextMenu cm = new ContextMenu();
cm.MenuItems.Add("1", (s,e) => {value = 1;});
cm.Show(control, location);
while (cm.Visible == true) Application.DoEvents();
0 голосов
/ 07 декабря 2011

Вы можете легко предотвратить сборку мусора в ContextMenu, пока он все еще отображается.

Проблема в том, что вы используете лямбду в качестве обработчика событий для пункта меню.Это анонимный метод, и поэтому он не привязан ни к какому экземпляру объекта, который бы вызывал обращение к ContextMenu и поддерживал его актуальность.Добавьте метод к включающему объекту, а затем создайте стандартный EventHandler.Таким образом, существование включающего экземпляра будет поддерживать ContextMenu живым.Не так лаконично и очень C # 1.0, но это решит проблему.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...