Procedura: gestire l'evento ContextMenuOpening

L'evento può essere gestito in un'applicazione per modificare un menu di scelta rapida esistente prima della visualizzazione o per eliminare il menu che verrebbe altrimenti visualizzato impostando la proprietà su nei dati ContextMenuOpening Handled true dell'evento. Il motivo tipico per cui si imposta su nei dati dell'evento è sostituire completamente il menu con un nuovo oggetto, che talvolta richiede l'annullamento dell'operazione e l'avvio Handled true di una nuova ContextMenu apertura. Se si scrivono gestori per l'evento , è necessario essere consapevoli dei problemi di temporizzazione tra un controllo e il servizio responsabile dell'apertura e del posizionamento dei menu di scelta rapida per i ContextMenuOpening ContextMenu controlli in generale. Questo argomento illustra alcune tecniche di codice per vari scenari di apertura del menu di scelta rapida e illustra un caso in cui entra in gioco il problema di temporizzazione.

Esistono diversi scenari per la gestione ContextMenuOpening dell'evento:

  • Regolazione delle voci di menu prima della visualizzazione.

  • Sostituzione dell'intero menu prima della visualizzazione.

  • Eliminazione completa di qualsiasi menu di scelta rapida esistente e visualizzazione di nessun menu di scelta rapida.

Esempio

Regolazione delle voci di menu prima della visualizzazione

La modifica delle voci di menu esistenti è piuttosto semplice ed è probabilmente lo scenario più comune. È possibile eseguire questa operazione per aggiungere o sottrarre le opzioni del menu di scelta rapida in risposta alle informazioni sullo stato corrente nell'applicazione o a particolari informazioni sullo stato disponibili come proprietà nell'oggetto in cui è richiesto il menu di scelta rapida.

La tecnica generale consiste nel ottenere l'origine dell'evento, ovvero il controllo specifico su cui è stato fatto clic con il pulsante destro del mouse, e ottenere ContextMenu la proprietà da esso. In genere si vuole controllare la raccolta per vedere quali voci di menu di scelta rapida esistono già nel menu e quindi aggiungere o rimuovere i nuovi elementi appropriati Items da o verso la MenuItem raccolta.

void AddItemToCM(object sender, ContextMenuEventArgs e)
{
    //check if Item4 is already there, this will probably run more than once
    FrameworkElement fe = e.Source as FrameworkElement;
    ContextMenu cm = fe.ContextMenu;
    foreach (MenuItem mi in cm.Items)
    {
        if ((String)mi.Header == "Item4") return;
    }
    MenuItem mi4 = new MenuItem();
    mi4.Header = "Item4";
    fe.ContextMenu.Items.Add(mi4);
}

Sostituzione dell'intero menu prima della visualizzazione

Uno scenario alternativo consiste nel sostituire l'intero menu di scelta rapida. È anche possibile usare una variante del codice precedente per rimuovere ogni elemento di un menu di scelta rapida esistente e aggiungerne di nuovi a partire dall'elemento zero. Tuttavia, l'approccio più intuitivo per sostituire tutte le voci nel menu di scelta rapida consiste nel creare un nuovo , popolarlo con elementi e quindi impostare la proprietà di un controllo come ContextMenu FrameworkElement.ContextMenu nuovo ContextMenu .

Di seguito è riportato il semplice codice del gestore per la sostituzione di un oggetto ContextMenu . Il codice fa riferimento a un metodo personalizzato, separato perché viene chiamato da più gestori BuildMenu di esempio.

void HandlerForCMO(object sender, ContextMenuEventArgs e)
{
    FrameworkElement fe = e.Source as FrameworkElement;
    fe.ContextMenu = BuildMenu();
}
ContextMenu BuildMenu()
{
    ContextMenu theMenu = new ContextMenu();
    MenuItem mia = new MenuItem();
    mia.Header = "Item1";
    MenuItem mib = new MenuItem();
    mib.Header = "Item2";
    MenuItem mic = new MenuItem();
    mic.Header = "Item3";
    theMenu.Items.Add(mia);
    theMenu.Items.Add(mib);
    theMenu.Items.Add(mic);
    return theMenu;
}

Tuttavia, se si usa questo stile di gestore per , è possibile esporre un problema di temporizzazione se l'oggetto in cui si sta impostando non dispone di un menu di ContextMenuOpening ContextMenu scelta rapida preesistente. Quando un utente fa clic con il pulsante destro del mouse su un controllo , viene generato anche se l'oggetto esistente ContextMenuOpening ContextMenu è vuoto o Null. In questo caso, tuttavia, qualsiasi nuovo ContextMenu elemento impostato nell'elemento di origine arriva troppo tardi per essere visualizzato. Inoltre, se l'utente fa clic con il pulsante destro del mouse una seconda volta, questa volta viene visualizzato il nuovo, il valore è diverso da Null e il gestore sostituirà e visualizza correttamente il menu quando il gestore viene eseguito una seconda ContextMenu volta. Ciò suggerisce due possibili soluzioni alternative:

  1. Assicurare che i gestori siano sempre eseguiti su controlli che hanno almeno un segnaposto disponibile, che si intende sostituire ContextMenuOpening con il codice del ContextMenu gestore. In questo caso, è comunque possibile usare il gestore illustrato nell'esempio precedente, ma in genere si vuole assegnare un ContextMenu segnaposto nel markup iniziale:

    <StackPanel>
      <Rectangle Fill="Yellow" Width="200" Height="100" ContextMenuOpening="HandlerForCMO">
        <Rectangle.ContextMenu>
          <ContextMenu>
            <MenuItem>Initial menu; this will be replaced ...</MenuItem>
          </ContextMenu>
        </Rectangle.ContextMenu>
      </Rectangle>
      <TextBlock>Right-click the rectangle above, context menu gets replaced</TextBlock>
    </StackPanel>
    
  2. Si supponga che il ContextMenu valore iniziale sia Null, in base a una logica preliminare. È possibile verificare la presenza di null o usare un flag nel codice per verificare se il gestore ContextMenu è stato eseguito almeno una volta. Poiché si presuppone che ContextMenu l'oggetto sta per essere visualizzato, il gestore imposta Handled quindi su nei dati true dell'evento. Per l'oggetto responsabile della visualizzazione del menu di scelta rapida, un valore per nei dati dell'evento rappresenta una richiesta di annullamento della visualizzazione per la combinazione di menu di scelta rapida/controllo che ha generato ContextMenuService true Handled l'evento.

Dopo aver eliminato il menu di scelta rapida potenzialmente sospetto, il passaggio successivo consiste nel specificarne uno nuovo e quindi visualizzarlo. L'impostazione del nuovo è fondamentalmente la stessa del gestore precedente: si compila un nuovo oggetto e si imposta la proprietà ContextMenu dell'origine FrameworkElement.ContextMenu del controllo con esso. Il passaggio aggiuntivo è che è ora necessario forzare la visualizzazione del menu di scelta rapida, perché è stato eliminato il primo tentativo. Per forzare la visualizzazione, impostare la Popup.IsOpen proprietà su true all'interno del gestore. Prestare attenzione quando si esegue questa operazione, perché l'apertura del menu di scelta rapida nel gestore genera nuovamente ContextMenuOpening l'evento . Se si reim annota il gestore, diventa infinitamente ricorsivo. Questo è il motivo per cui è sempre necessario cercare o usare un flag se si apre un menu di scelta null rapida dall'interno di ContextMenuOpening un gestore eventi.

Eliminazione di qualsiasi menu di scelta rapida esistente e visualizzazione di nessun menu di scelta rapida

Lo scenario finale, la scrittura di un gestore che elimina completamente un menu, non è comune. Se un determinato controllo non deve visualizzare un menu di scelta rapida, esistono probabilmente modi più appropriati per garantirlo piuttosto che eliminare il menu solo quando un utente lo richiede. Se tuttavia si vuole usare il gestore per eliminare un menu di scelta rapida e non visualizzare alcun elemento, il gestore deve semplicemente impostare Handled su true nei dati dell'evento. L'oggetto responsabile della visualizzazione di un menu di scelta rapida controlla i dati dell'evento generato ContextMenuService sul controllo. Se l'evento è stato contrassegnato in un punto qualsiasi lungo la route, l'azione di apertura del menu di scelta Handled rapida che ha avviato l'evento viene eliminata.

    void HandlerForCMO2(object sender, ContextMenuEventArgs e)
    {
        if (!FlagForCustomContextMenu)
        {
            e.Handled = true; //need to suppress empty menu
            FrameworkElement fe = e.Source as FrameworkElement;
            fe.ContextMenu = BuildMenu();
            FlagForCustomContextMenu = true;
            fe.ContextMenu.IsOpen = true;
        }
    }
}

Vedi anche