Bestimmen Sie, auf welchem ​​Steuerelement der ContextMenuStrip verwendet wurde

84

Ich habe eine ContextMenuStrip, die mehreren verschiedenen Listenfeldern zugeordnet ist. Ich versuche herauszufinden, wann auf das ContextMenuStripgeklickt wird, worauf ListBoxes verwendet wurde. Ich habe den folgenden Code zunächst einmal ausprobiert, aber er funktioniert nicht. Das senderhat den richtigen Wert, aber wenn ich versuche, es dem zuzuweisen, menuSubmittedist es null.

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

Jede Hilfe wäre großartig. Vielen Dank.

Mit der folgenden Hilfe habe ich es herausgefunden:

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
quelle
Danke für die Lösung, die ich gesucht habe. Ich hatte das gleiche Problem. Aber ich schlage vor, nicht alle diese ifAnweisungen if (menuItem == null) return;zu verschachteln und zu verwenden, wenn Sie wie ich sind und nicht möchten, dass Ihr Code, der damit umgeht, um zusätzliche unnötige 2 Ebenen verschachtelt wird.
Shawn Kovac

Antworten:

121

Für eine ContextMenu:

Das Problem ist, dass der senderParameter auf das Element im Kontextmenü zeigt, auf das geklickt wurde, und nicht auf das Kontextmenü selbst.

Es ist jedoch eine einfache Lösung, da jede MenuItemeine GetContextMenuMethode verfügbar macht , die Ihnen sagt, welcheContextMenu diesen Menüpunkt enthält.

Ändern Sie Ihren Code wie folgt:

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

Für eine ContextMenuStrip:

Es ändert sich geringfügig, wenn Sie a ContextMenuStripanstelle von a verwenden ContextMenu. Die beiden Steuerelemente sind nicht miteinander verknüpft, und eine Instanz des einen kann nicht in eine Instanz des anderen umgewandelt werden.

Nach wie vor wird das angeklickte Element weiterhin im senderParameter zurückgegeben, sodass Sie bestimmen müssen ContextMenuStrip, wem dieses einzelne Menüelement gehört. Das machen Sie mit der OwnerImmobilie . Schließlich bestimmen Sie anhand der SourceControlEigenschaft, auf welchem ​​Steuerelement das Kontextmenü angezeigt wird.

Ändern Sie Ihren Code wie folgt:

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 Grey
quelle
@bluefeet: Dann hast du was anderes falsch gemacht. Ich habe diesen Code gerade mit drei verschiedenen Listenfeldern getestet und alles hat wie erwartet funktioniert. Poste etwas mehr Repro-Code.
Cody Gray
1
@bluefeet: Ich habe den Code in meiner Antwort aktualisiert. Es gibt einen großen Unterschied zwischen ContextMenuund ContextMenuStrip. (Ah, und ich sehe, Sie haben es bereits herausgefunden. Umso besser, Dinge selbst zu lernen!)
Cody Gray
1
Ich habe das Ereignis "Öffnen" verwendet, um das SourceControl aufzuzeichnen, mit dem das Menü für eine lokale Variable geöffnet wurde, und habe dann beim Behandeln von Elementklicks darauf verwiesen.
QuickDanger
1
@QuickDanger Ja, SourceControlist leider null, wenn ein ClickEreignis eines Unterelements ToolStripItemvon ContextMenuStripausgelöst wird. Es scheint , dass die ContextMenuStrips‘ ClosedEreignis ausgelöst wird vor diesem ClickEreignis, das wahrscheinlich ist , was das Problem verursacht; Ich gehe davon aus, dass die Eigenschaft gelöscht wird, nachdem das Menü geschlossen wird.
Nyerguds
1
@CodyGray Wenn der Baum tiefer ist, müssen Sie die OwnerItemEigenschaftskette durchlaufen, bis Sie eine finden ToolStripItem, ContextMenuStripderen OwnerEigenschaft a enthält. Aber wie ich gerade kommentiert habe, funktioniert es nicht; Das SourceControlim Kontextmenü ist null. Sie sagten, Sie können es jedoch nicht reproduzieren ... Vielleicht tritt das Problem nur bei Menüs auf, die tiefer als eine Ebene liegen? Meins war zwei Unterebenen tief.
Nyerguds
3

Älterer Beitrag, aber falls jemand wie ich darauf stößt:

Bei einem ContextMenuStrip hat das oben Genannte bei mir nicht funktioniert, aber es hat dazu geführt, dass ich herausgefunden habe, was funktioniert hat.

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

Dies gab mir den Namen der erwarteten Kontrolle. Sie können eine Validierung usw. mit if-Anweisungen vornehmen. Ich poste nur, um auf den Punkt zu kommen.

seanu13
quelle
Dies funktioniert nur mit den direkten Elementen in a ContextMenu. Das Problem ist, dass ItemClickedbeim Klicken auf Untermenüelemente nicht ausgelöst wird . Sie benötigen ein eigenes ClickEreignis, bei dem der Artikel selbst als Absender und nicht das Menü angezeigt wird.
Nyerguds
3

Ich hatte große Schwierigkeiten, diesen Code zum Laufen zu bringen. Dies ist die einfachste Lösung, die ich finden konnte:

Für einen 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
quelle
0

Die einfachste Lösung wäre:

Control parentControl = ((sender as MenuItem).GetContextMenu()).SourceControl;
 
Emile gegen Rooyen
quelle