Определите, на каком элементе управления ContextMenuStrip использовался

85

У меня есть, ContextMenuStripкоторый назначен на несколько разных списков. Я пытаюсь понять, когда ContextMenuStripнажимается, для чего ListBoxон был использован. Для начала я попробовал приведенный ниже код, но он не работает. senderИмеет правильное значение, но когда я пытаюсь назначить его на menuSubmittedэто нуль.

private void MenuViewDetails_Click(object sender, EventArgs e)
{
    ContextMenu menuSubmitted = sender as ContextMenu;
    if (menuSubmitted != null)
    {
        Control sourceControl = menuSubmitted.SourceControl;
    }
}

Любая помощь была бы замечательной. Благодарю.

Используя приведенную ниже помощь, я понял это:

private void MenuViewDetails_Click(object sender, EventArgs e)
        {
            ToolStripMenuItem menuItem = sender as ToolStripMenuItem;
            if (menuItem != null)
            {
                ContextMenuStrip calendarMenu = menuItem.Owner as ContextMenuStrip;

                if (calendarMenu != null)
                {
                    Control controlSelected = calendarMenu.SourceControl;
                }
            }
        }
Тарин
источник
спасибо за решение, которое я искал. У меня такая же проблема. но я предлагаю не вкладывать все эти ifоператоры и не использовать их, if (menuItem == null) return;если вы похожи на меня и не хотите, чтобы ваш код, который его обрабатывает, был вложен в дополнительные ненужные 2 уровня.
Шон Ковач

Ответы:

126

Для ContextMenu:

Проблема в том, что senderпараметр указывает на элемент в контекстном меню, который был нажат, а не на само контекстное меню.

Однако это простое исправление, потому что каждый из них MenuItemпредоставляет GetContextMenuметод , который скажет вам, какойContextMenu элементе меню находится этот пункт.

Измените свой код на следующий:

private void MenuViewDetails_Click(object sender, EventArgs e)
{
    // Try to cast the sender to a MenuItem
    MenuItem menuItem = sender as MenuItem;
    if (menuItem != null)
    {
        // Retrieve the ContextMenu that contains this MenuItem
        ContextMenu menu = menuItem.GetContextMenu();

        // Get the control that is displaying this context menu
        Control sourceControl = menu.SourceControl;
    }
}

Для ContextMenuStrip:

Это немного меняет ситуацию, если вы используете ContextMenuStripвместо ContextMenu. Два элемента управления не связаны друг с другом, и экземпляр одного не может быть преобразован в экземпляр другого.

Как и раньше, элемент, по которому был выполнен щелчок, по-прежнему возвращается в senderпараметре, поэтому вам нужно будет определить ContextMenuStrip, кому принадлежит этот отдельный элемент меню. Вы делаете это с Ownerсобственностью . Наконец, вы будете использовать SourceControlсвойство, чтобы определить, какой элемент управления отображает контекстное меню.

Измените свой код так:

private void MenuViewDetails_Click(object sender, EventArgs e)
{
     // Try to cast the sender to a ToolStripItem
     ToolStripItem menuItem = sender as ToolStripItem;
     if (menuItem != null)
     {
        // Retrieve the ContextMenuStrip that owns this ToolStripItem
        ContextMenuStrip owner = menuItem.Owner as ContextMenuStrip;
        if (owner != null)
        {
           // Get the control that is displaying this context menu
           Control sourceControl = owner.SourceControl;
        }
     }
 }
Коди Грей
источник
@bluefeet: Значит, у тебя еще что-то не так. Я только что протестировал этот код с тремя разными списками, и все заработало, как ожидалось. Разместите еще несколько репро-кода.
Коди Грей
2
@bluefeet: Я обновил код в своем ответе. Есть большая разница между ContextMenuи ContextMenuStrip. (Ах, и я вижу, что вы уже поняли это. Что ж, тем лучше научиться чему-то самому!)
Коди Грей
1
Я использовал событие открытия для записи SourceControl, открывающего меню для локальной переменной, а затем ссылался на это при обработке щелчков по элементам.
QuickDanger 08
1
@QuickDanger Да, к SourceControlсожалению , имеет значение null в момент запуска Clickсобытия ToolStripItemподпункта ContextMenuStrip. Кажется , что ContextMenuStrip«S Closedсобытие срабатывает до этого Clickсобытия, которое, вероятно , что вызывает проблему; Я предполагаю, что свойство очищается после закрытия меню.
Nyerguds 02
1
@CodyGray На самом деле, если дерево глубже, вам нужно перебирать цепочку OwnerItemсвойств, пока не найдете ToolStripItem, ContextMenuStripв Ownerсвойстве которого есть a . Но, как я только что прокомментировал, это не работает; в SourceControlконтекстном меню будет пусто. Вы сказали, что не можете воспроизвести это ... может проблема возникает только с меню глубже одного уровня? У меня было два подуровня.
Nyerguds 02
4

Предыдущий пост, но на случай, если кто-то вроде меня наткнется на него:

Для ContextMenuStrip это не сработало для меня, но привело к обнаружению того, что сработало.

void DeleteMenu_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
{
    ContextMenuStrip menu = sender as ContextMenuStrip;
    Control sourceControl = menu.SourceControl;
    MessageBox.Show(sourceControl.Name);
}

Это дало мне имя ожидаемого элемента управления. Вы можете включить проверку и т. Д. С помощью операторов if, я просто публикую, чтобы перейти к сути.

seanu13
источник
Это работает только с прямыми элементами в ContextMenu. Проблема в том, что ItemClickedне срабатывает при нажатии на пункты подменю ; им нужно собственное Clickсобытие, в котором отправителем будет сам элемент, а не меню.
Nyerguds 02
3

Мне было очень трудно заставить любой из этих кодов работать. Это самое простое решение, которое я смог найти:

Для ContextMenuStrip:

    Control _sourceControl = null;
    private void contextMenuStrip_Opened(object sender, EventArgs e)
    {
        _sourceControl = contextMenuStrip.SourceControl;
    }

    private void contextMenuItem_Click(object sender, EventArgs e)
    {
        var menuItem = (ToolStripMenuItem)sender;

        _sourceControl.Text = menuItem.Text;
        MessageBox.Show(menuItem.Name);
        MessageBox.Show(sourceControl.Name);
    }
Ник Аллан
источник
0

Самым простым решением было бы:

Control parentControl = ((sender as MenuItem).GetContextMenu()).SourceControl;
 
Эмиль v Ройен
источник