Determina su quale controllo è stato utilizzato ContextMenuStrip


85

Ho un ContextMenuStripche è assegnato a diverse caselle di riepilogo. Sto cercando di capire quando ContextMenuStripviene cliccato su cosa ListBoxè stato utilizzato. Ho provato il codice seguente come inizio ma non funziona. Il senderha il valore corretto, ma quando provo ad assegnare al menuSubmittedè nullo.

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

Qualsiasi aiuto sarebbe grande. Grazie.

Usando l'assistenza di seguito, ho capito:

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

grazie per la soluzione che stavo cercando. Ho avuto lo stesso problema. ma suggerisco di non annidare tutte quelle ifistruzioni e di usarle if (menuItem == null) return;se sei come me e non vuoi che il tuo codice che lo gestisce sia annidato di 2 livelli extra inutili.
Shawn Kovac

Risposte:


126

Per un ContextMenu:

Il problema è che il senderparametro punta alla voce del menu contestuale su cui si è fatto clic, non al menu contestuale stesso.

È una soluzione semplice, tuttavia, perché ognuno MenuItemespone un GetContextMenumetodo che ti dirà quale ContextMenucontiene quella voce di menu.

Cambia il tuo codice come segue:

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

Per un ContextMenuStrip:

Cambia leggermente le cose se usi a ContextMenuStripinvece di ContextMenu. I due controlli non sono correlati tra loro e non è possibile eseguire il cast di un'istanza di uno in un'istanza dell'altro.

Come prima, l' elemento su cui si è fatto clic viene comunque restituito nel senderparametro, quindi sarà necessario determinare il ContextMenuStripproprietario di questa singola voce di menu. Lo fai con la Ownerproprietà . Infine, utilizzerai la SourceControlproprietà per determinare quale controllo sta visualizzando il menu di scelta rapida.

Modifica il tuo codice in questo modo:

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: Allora hai qualcos'altro che non va. Ho appena testato questo codice con tre diverse caselle di riepilogo e tutto ha funzionato come previsto. Pubblica altro codice di riproduzione.
Cody Grey

2
@ bluefeet: ho aggiornato il codice nella mia risposta. C'è una grande differenza tra ContextMenue ContextMenuStrip. (Ah, e vedo che l'hai già capito. Bene, tanto meglio imparare le cose da solo!)
Cody Grey

1
Ho utilizzato l'evento di apertura per registrare il SourceControl che ha aperto il menu su una variabile locale, quindi ho fatto riferimento a questo quando gestivo i clic sugli elementi.
QuickDanger

1
@QuickDanger Sì, SourceControlpurtroppo è nullo al momento in cui viene generato un Clickevento di un ToolStripItemsottoelemento di ContextMenuStrip. Sembra che il ContextMenuStrip's Closedgenerato l'evento prima che Clickevento, che è probabilmente quello che causa il problema; Presumo che la proprietà venga cancellata dopo la "chiusura" del menu.
Nyerguds

1
@CodyGray In realtà, se l'albero è più profondo, devi eseguire il loop della catena di OwnerItemproprietà finché non trovi un ToolStripItemche ha un ContextMenuStripnella sua Ownerproprietà. Ma come ho appena commentato, non funziona; il SourceControlnel menu contestuale sarà nullo. Hai detto che non puoi riprodurlo ... forse il problema si verifica solo con menu più profondi di un livello? Il mio era profondo due sottolivelli.
Nyerguds

4

Post più vecchio, ma nel caso qualcuno come me lo trovi:

Per un ContextMenuStrip, quanto sopra non ha funzionato per me, ma ha portato a scoprire cosa funzionava.

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

Questo mi ha dato il nome del controllo previsto. Puoi inserire la convalida ecc. Con le istruzioni if, sto solo postando per arrivare al punto.


Funziona solo con gli elementi diretti in un file ContextMenu. Il problema è che ItemClickednon si attiva quando si fa clic sugli elementi del sottomenu ; hanno bisogno del proprio Clickevento che abbia l'elemento stesso come mittente, non il menu.
Nyerguds

3

Ho avuto grandi difficoltà a far funzionare tutto questo codice. Questa è la soluzione più semplice che ho trovato:

Per un 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

La soluzione più semplice sarebbe:

Control parentControl = ((sender as MenuItem).GetContextMenu()).SourceControl;
 
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.