Procedura: Gestire l'evento ContextMenuOpeningHow to: Handle the ContextMenuOpening Event

Il ContextMenuOpening evento può essere gestito in un'applicazione per modificare un esistente prima di menu di scelta rapida per visualizzare o eliminare il menu che verrà altrimenti visualizzato impostando il Handled proprietà true nei dati dell'evento.The ContextMenuOpening event can be handled in an application to either adjust an existing context menu prior to display or to suppress the menu that would otherwise be displayed by setting the Handled property to true in the event data. La ragione più comune per l'impostazione Handled al true dei dati nell'evento consiste nella sostituzione menu interamente con un nuovo ContextMenu dell'oggetto, che a volte richiede l'annullamento dell'operazione e l'avvio di un nuovo open.The typical reason for setting Handled to true in the event data is to replace the menu entirely with a new ContextMenu object, which sometimes requires canceling the operation and starting a new open. Se si scrivono i gestori per il ContextMenuOpening evento, è necessario essere consapevoli dei problemi di temporizzazione tra un ContextMenu controllo e il servizio che è responsabile dell'apertura e il posizionamento di menu di scelta rapida per i controlli in generale.If you write handlers for the ContextMenuOpening event, you should be aware of timing issues between a ContextMenu control and the service that is responsible for opening and positioning context menus for controls in general. In questo argomento vengono illustrate alcune delle tecniche di codice per scenari di apertura dei vari menu di scelta rapida e viene illustrato un caso in cui il problema di temporizzazione entra in gioco.This topic illustrates some of the code techniques for various context menu opening scenarios and illustrates a case where the timing issue comes into play.

Esistono diversi scenari per la gestione di ContextMenuOpening evento:There are several scenarios for handling the ContextMenuOpening event:

  • Modificare le voci di menu prima della visualizzazione.Adjusting the menu items before display.

  • Sostituire l'intero menu prima della visualizzazione.Replacing the entire menu before display.

  • Completamente l'eliminazione di qualsiasi menu di scelta rapida esistente e non visualizzare alcun menu di scelta rapida.Completely suppressing any existing context menu and displaying no context menu.

EsempioExample

Modificare le voci di Menu prima della visualizzazioneAdjusting the Menu Items Before Display

Modificando le voci di menu esistente è piuttosto semplice e probabilmente lo scenario più comune.Adjusting the existing menu items is fairly simple and is probably the most common scenario. È possibile farlo per poter aggiungere o sottrarre le opzioni di menu di scelta rapida in risposta alle informazioni sullo stato corrente dell'applicazione o informazioni sullo stato determinato che sono disponibile come una proprietà dell'oggetto in cui viene richiesto il menu di scelta rapida.You might do this in order to add or subtract context menu options in response to current state information in your application or particular state information that is available as a property on the object where the context menu is requested.

La tecnica generale consiste nell'ottenere l'origine dell'evento, vale a dire il controllo specifico acquisendone, e Ottieni la ContextMenu proprietà da quest'ultimo.The general technique is to get the source of the event, which is the specific control that was right-clicked, and get the ContextMenu property from it. In genere si vuole controllare la Items insieme per vedere quali voci di menu di scelta rapida già esiste nel menu e quindi aggiungere o rimuovere appropriato new MenuItem da o verso la raccolta di elementi.You typically want to check the Items collection to see what context menu items already exist in the menu, and then add or remove appropriate new MenuItem items to or from the collection.

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

Sostituire l'intero Menu prima della visualizzazioneReplacing the Entire Menu Before Display

Uno scenario alternativo è se si desidera sostituire il menu di scelta rapida intero.An alternative scenario is if you want to replace the entire context menu. Naturalmente è possibile usare anche una variante del codice precedente, per rimuovere ogni elemento di un menu di scelta rapida esistente e aggiungerne di nuovi, iniziando dall'elemento zero.You could of course also use a variation of the preceding code, to remove every item of an existing context menu and add new ones starting with item zero. Ma l'approccio più intuitiva per la sostituzione di tutti gli elementi nel menu di scelta rapida consiste nel creare una nuova ContextMenuviene popolato con gli elementi e quindi impostare il FrameworkElement.ContextMenu proprietà di un controllo che sarà il nuovo ContextMenu.But the more intuitive approach for replacing all items in the context menu is to create a new ContextMenu, populate it with items, and then set the FrameworkElement.ContextMenu property of a control to be the new ContextMenu.

Di seguito è riportato il codice del gestore semplice per la sostituzione di un ContextMenu.The following is the simple handler code for replacing a ContextMenu. Il codice fa riferimento a un oggetto personalizzato BuildMenu metodo, che è separato perché viene chiamato da più di uno dei gestori di esempio.The code references a custom BuildMenu method, which is separated out because it is called by more than one of the example handlers.

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 utilizza questo stile di visualizzazione del gestore per ContextMenuOpening, si può esporre potenzialmente un problema di temporizzazione se l'oggetto in cui si sta impostando il ContextMenu non dispone di un menu di scelta rapida preesistenti.However, if you use this style of handler for ContextMenuOpening, you can potentially expose a timing issue if the object where you are setting the ContextMenu does not have a preexisting context menu. Quando un utente fa clic di un controllo ContextMenuOpening viene generato anche se l'oggetto esistente ContextMenu è vuoto o null.When a user right-clicks a control, ContextMenuOpening is raised even if the existing ContextMenu is empty or null. Ma in questo caso, qualsiasi nuovo ContextMenu è impostata sull'origine elemento arriva troppo tardi per poter essere visualizzati.But in this case, whatever new ContextMenu you set on the source element arrives too late to be displayed. Inoltre, se l'utente a fare doppio clic su una seconda volta, questa volta il nuovo ContextMenu visualizzata, il valore è non null e il gestore verrà sostituire correttamente e verrà visualizzato il menu di scelta quando il gestore esegue una seconda volta.Also, if the user happens to right-click a second time, this time your new ContextMenu appears, the value is non null, and your handler will properly replace and display the menu when the handler runs a second time. Ciò suggerisce possibili due soluzioni alternative:This suggests two possible workarounds:

  1. Assicurarsi che ContextMenuOpening gestori di eseguire sempre i controlli che hanno almeno un segnaposto ContextMenu disponibili, che si prevede essere sostituito con il codice del gestore.Insure that ContextMenuOpening handlers always run against controls that have at least a placeholder ContextMenu available, which you intend to be replaced by the handler code. In questo caso, è comunque possibile usare il gestore illustrato nell'esempio precedente, ma in genere si vuole assegnare un segnaposto ContextMenu nel markup iniziale:In this case, you can still use the handler shown in the previous example, but you typically want to assign a placeholder ContextMenu in the initial markup:

    <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 iniziale ContextMenu valore potrebbe essere null, basato su logica preliminare.Assume that the initial ContextMenu value might be null, based on some preliminary logic. È possibile archiviarla ContextMenu è null o usare un flag nel codice per verificare se il gestore di è stato eseguito almeno una volta.You could either check ContextMenu for null, or use a flag in your code to check whether your handler has been run at least once. Poiché si presuppone che il ContextMenu sta per essere visualizzato, il gestore quindi imposta Handled a true nei dati dell'evento.Because you assume that the ContextMenu is about to be displayed, your handler then sets Handled to true in the event data. Per il ContextMenuService responsabile per la visualizzazione di menu di scelta rapida, una true value per Handled nell'evento dati rappresentano una richiesta di annullare la visualizzazione per il menu di scelta / controllo combinazione che ha generato l'evento.To the ContextMenuService that is responsible for context menu display, a true value for Handled in the event data represents a request to cancel the display for the context menu / control combination that raised the event.

Dopo aver eliminato il menu di scelta rapida potenzialmente sospetti, il passaggio successivo è fornire uno nuovo, quindi visualizzarlo.Now that you have suppressed the potentially suspect context menu, the next step is to supply a new one, then display it. L'impostazione di nuovo uno è fondamentalmente lo stesso come il gestore precedente: si crea un nuovo ContextMenu e impostare l'origine di controllo FrameworkElement.ContextMenu proprietà con esso.Setting the new one is basically the same as the previous handler: you build a new ContextMenu and set the control source's FrameworkElement.ContextMenu property with it. Il passaggio aggiuntivo è che ora è necessario forzare la visualizzazione del menu di scelta rapida, perché è stato evitato al primo tentativo.The additional step is that you must now force the display of the context menu, because you suppressed the first attempt. Per forzare la visualizzazione, si imposta la Popup.IsOpen proprietà true all'interno del gestore.To force the display, you set the Popup.IsOpen property to true within the handler. Prestare attenzione quando si esegue questa operazione, poiché aprendo il menu di scelta rapida nel gestore genera il ContextMenuOpening nuovo evento.Be careful when you do this, because opening the context menu in the handler raises the ContextMenuOpening event again. Se si accede nuovamente al gestore, diventa infinitamente ricorsiva.If you reenter your handler, it becomes infinitely recursive. Ecco perché è sempre necessario verificare la presenza null oppure usare un flag, se si apre un menu di scelta rapida dall'interno una ContextMenuOpening gestore dell'evento.This is why you always need to check for null or use a flag if you open a context menu from within a ContextMenuOpening event handler.

Eliminazione di qualsiasi menu di scelta rapida esistente e non visualizzare alcun menu di scelta rapidaSuppressing Any Existing Context Menu and Displaying No Context Menu

Nello scenario finale, scrivere un gestore che elimina completamente, un menu è insolito.The final scenario, writing a handler that suppresses a menu totally, is uncommon. Se un determinato controllo non deve per visualizzare un menu di scelta rapida, esistono modi probabilmente più appropriati per assicurare che questa rispetto all'eliminazione del menu solo quando un utente lo richiede.If a given control is not supposed to display a context menu, there are probably more appropriate ways to assure this than by suppressing the menu just when a user requests it. Se si desidera utilizzare il gestore per eliminare un menu di scelta rapida e non visualizzare nulla, allora il gestore di è sufficiente deve impostare Handled a true nei dati dell'evento.But if you want to use the handler to suppress a context menu and show nothing, then your handler should simply set Handled to true in the event data. Il ContextMenuService che è responsabile della visualizzazione di un menu di scelta rapida controllerà i dati dell'evento dell'evento generato sul controllo.The ContextMenuService that is responsible for displaying a context menu will check the event data of the event it raised on the control. Se l'evento è stato contrassegnato come Handled in qualsiasi punto lungo la route, quindi l'azione di Apri menu di scelta rapida che ha avviato l'evento viene eliminato.If the event was marked Handled anywhere along the route, then the context menu open action that initiated the event is suppressed.

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

Vedere ancheSee also