Określ, na jakiej kontrolce użyto ContextMenuStrip

84

Mam ContextMenuStripprzypisany do kilku różnych list. Próbuję dowiedzieć się, kiedy ContextMenuStripkliknięto, na czym ListBoxbył używany. Na początek wypróbowałem poniższy kod, ale nie działa. senderMa prawidłową wartość, ale gdy próbuję go przypisać do menuSubmittedto jest null.

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

Każda pomoc byłaby świetna. Dzięki.

Korzystając z poniższej pomocy, rozgryzłem to:

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;
                }
            }
        }
Taryn
źródło
dzięki za rozwiązanie, którego szukałem. miałem ten sam problem. ale radzę nie zagnieżdżać wszystkich tych ifinstrukcji i używać, if (menuItem == null) return;jeśli jesteś podobny do mnie i nie chcesz, aby twój kod, który go obsługuje, był zagnieżdżony na dodatkowych niepotrzebnych 2 poziomach.
Shawn Kovac

Odpowiedzi:

123

Dla ContextMenu:

Problem polega na tym, że senderparametr wskazuje element w menu kontekstowym, które zostało kliknięte, a nie samo menu kontekstowe.

Jest to jednak prosta poprawka, ponieważ każda z nich MenuItemujawnia GetContextMenumetodę , która powie ci, która ContextMenuzawiera dany element menu.

Zmień kod na następujący:

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

Dla ContextMenuStrip:

Jeśli użyjesz a ContextMenuStripzamiast a ContextMenu. Te dwie kontrolki nie są ze sobą powiązane, a instancji jednej nie można rzutować na instancję drugiej.

Tak jak poprzednio, kliknięty element jest nadal zwracany w senderparametrze, więc będziesz musiał określić, do kogo należy ContextMenuStripten pojedynczy element menu. Robisz to z Ownernieruchomością . Na koniec użyjesz SourceControlwłaściwości do określenia, która kontrolka wyświetla menu kontekstowe.

Zmodyfikuj swój kod w następujący sposób:

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;
        }
     }
 }
Cody Gray
źródło
@bluefeet: Więc coś innego jest nie tak. Właśnie przetestowałem ten kod z trzema różnymi listboxami i wszystko działało zgodnie z oczekiwaniami. Opublikuj więcej kodu repro.
Cody Grey
2
@bluefeet: Zaktualizowałem kod w mojej odpowiedzi. Istnieje duża różnica między ContextMenui ContextMenuStrip. (Ach, i widzę, że już to rozgryzłeś. Cóż, tym lepiej jest uczyć się na własną rękę!)
Cody Gray
1
Użyłem zdarzenia Opening, aby zarejestrować SourceControl, które otworzyło menu do zmiennej lokalnej, a następnie odwołałem się do niej podczas obsługi kliknięć elementu.
QuickDanger,
1
@QuickDanger Yeah, SourceControlniestety jest zerowe w chwili, gdy uruchamiane jest Clickzdarzenie elementu ToolStripItempodrzędnego ContextMenuStrip. Wydaje się, że ContextMenuStrip„s ClosedZdarzenie przed tym Clickwydarzeniem, które jest chyba to, co powoduje ten problem; Zakładam, że nieruchomość jest czyszczona po zamknięciu menu.
Nyerguds
1
@CodyGray Właściwie, jeśli drzewo jest głębsze, musisz zapętlić łańcuch OwnerItemwłaściwości, aż znajdziesz obiekt, ToolStripItemktóry ma ContextMenuStripw swojej Ownerwłaściwości. Ale jak właśnie powiedziałem, to nie działa; w SourceControlmenu kontekstowym będzie mieć wartość null. Powiedziałeś, że nie możesz tego odtworzyć ... może problem występuje tylko w przypadku menu głębszych niż jeden poziom? Mój był głęboki na dwa poziomy.
Nyerguds
3

Starszy post, ale na wypadek, gdyby ktoś taki jak ja go spotkał:

W przypadku ContextMenuStrip powyższe nie działało dla mnie, ale doprowadziło do znalezienia tego, co zrobiło.

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

To dało mi oczekiwaną nazwę kontrolki. Możesz wprowadzić walidację itp. Za pomocą instrukcji if, po prostu piszę, aby przejść do sedna.

seanu13
źródło
Działa to tylko z bezpośrednimi elementami w pliku ContextMenu. Problem polega na tym, ItemClickedże nie uruchamia się po kliknięciu elementów podmenu ; potrzebują własnego Clickwydarzenia, które miałoby samą pozycję jako nadawcę, a nie menu.
Nyerguds
3

Miałem duże trudności z uruchomieniem któregokolwiek z tych kodów. Oto najprostsze rozwiązanie, jakie udało mi się znaleźć:

W przypadku 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);
    }
Nick Allan
źródło
0

Najłatwiejszym rozwiązaniem byłoby:

Control parentControl = ((sender as MenuItem).GetContextMenu()).SourceControl;
 
Emile przeciwko Rooyen
źródło