Визначте, на якому контролі було використано ContextMenuStrip


84

У мене є, 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 рівнями.
Шон Ковач

Відповіді:


123

Для 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замість a 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
Я використовував подію Opening для запису SourceControl, який відкривав меню для локальної змінної, а потім посилався на це при обробці клацань на елементі.
QuickDanger

1
@QuickDanger Так, SourceControlна жаль, нуль на момент запуску Clickподії ToolStripItemпідпункту ContextMenuStrip. Здається , що ContextMenuStrip«S Closedподія спрацьовує до цього Clickподії, яке, ймовірно , що викликає проблему; Я припускаю, що властивість очищається після того, як меню закривається.
Nyerguds,

1
@CodyGray Насправді, якщо дерево глибше, вам доведеться зациклювати ланцюжок OwnerItemвластивостей, поки не знайдете a, ToolStripItemщо має ContextMenuStripу своїй Ownerвластивості. Але як я щойно прокоментував, це не працює; у SourceControlконтекстному меню буде нульовим. Ви сказали, що не можете його відтворити ... можливо, проблема виникає лише в меню глибше одного рівня? Мій був глибиною два підрівні.
Nyerguds,

3

Старіша публікація, але на випадок, якщо хтось на зразок мене натрапить:

Для ContextMenuStrip вищезазначене для мене не працювало, але це призвело до пошуку того, що було.

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

Це дало мені очікуване ім’я контролю. Ви можете ввести валідацію і т. Д. Із твердженнями if, я просто публікую, щоб перейти до суті.


Це працює лише з прямими елементами в ContextMenu. Проблема в тому, що ItemClickedне спрацьовує при натисканні на елементи підменю ; їм потрібна власна Clickподія, в якій відправником буде сам елемент, а не меню.
Nyerguds,

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);
    }

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.