Procedimiento Controlar el evento ContextMenuOpeningHow to: Handle the ContextMenuOpening Event

El ContextMenuOpening se pueden controlar eventos en una aplicación para ajustar un menú contextual existente antes para mostrar o suprimir el menú que se mostraría en caso contrario, estableciendo el Handled propiedad true en los datos del 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 razón típica para la configuración de Handled a true en el evento son reemplazar el menú completamente con un nuevo datos ContextMenu objeto, que a veces requiere cancelar la operación e iniciar una nuevo abrir.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. Al escribir controladores para la ContextMenuOpening eventos, debe ser consciente de los problemas de sincronización entre un ContextMenu control y el servicio que se encarga de abrir y posicionamiento de los menús contextuales para los controles en general.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. En este tema se muestra algunas de las técnicas de código para el menú contextual de varios escenarios de apertura y muestra un caso donde el problema de sincronización entra en juego.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.

Hay varios escenarios para el control de la ContextMenuOpening eventos:There are several scenarios for handling the ContextMenuOpening event:

  • Ajuste de los elementos de menú antes de la presentación.Adjusting the menu items before display.

  • Reemplazar el menú completo antes de la presentación.Replacing the entire menu before display.

  • Suprimir cualquier menú contextual existente y no mostrar ningún menú contextual por completo.Completely suppressing any existing context menu and displaying no context menu.

EjemploExample

Ajuste de los elementos de menú antes de la presentaciónAdjusting the Menu Items Before Display

Ajuste de los elementos de menú existentes es bastante simple y es probablemente el escenario más común.Adjusting the existing menu items is fairly simple and is probably the most common scenario. Puede hacerlo con el fin de agregar o restar las opciones del menú contextual en respuesta a la información de estado actual de la aplicación o información de estado concreta que está disponible como una propiedad del objeto donde se solicita el menú contextual.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 técnica general consiste en obtener el origen del evento, que es el control específico que hizo, y obtener el ContextMenu propiedad a partir de él.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. Normalmente desea comprobar la Items colección para ver qué elementos de menú contextual ya existe en el menú y, a continuación, agregar o quitar adecuado nuevo MenuItem hacia o desde la colección de elementos.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);
}

Reemplazar el menú completo antes de la presentaciónReplacing the Entire Menu Before Display

Un escenario alternativo es si desea reemplazar el menú contextual completo.An alternative scenario is if you want to replace the entire context menu. Desde luego también puede usar una variación del código anterior, para quitar todos los elementos de un menú contextual existente y agregar otros nuevos a partir de cero del elemento.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. Pero es el enfoque más intuitivo para reemplazar todos los elementos en el menú contextual crear un nuevo ContextMenu, rellenarlo con elementos y, a continuación, establezca el FrameworkElement.ContextMenu propiedad de un control como el nuevo 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.

El siguiente es el código del controlador simple para reemplazar un ContextMenu.The following is the simple handler code for replacing a ContextMenu. El código hace referencia a un personalizado BuildMenu método, que se separaron porque se llama mediante más de uno de los controladores de ejemplo.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;
}

Sin embargo, si usa este estilo de controlador para ContextMenuOpening, puede quedar expuesto un problema de sincronización si el objeto que está configurando el ContextMenu no tiene un menú contextual preexistente.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. Cuando un usuario hace clic con botón de un control, ContextMenuOpening se produce incluso si existente ContextMenu está vacío o nulo.When a user right-clicks a control, ContextMenuOpening is raised even if the existing ContextMenu is empty or null. Pero en este caso, cualquier nuevo ContextMenu se establece en el origen de elemento llega demasiado tarde para mostrarse.But in this case, whatever new ContextMenu you set on the source element arrives too late to be displayed. Además, si el usuario que hace clic en una segunda vez, esta vez la nueva ContextMenu aparece, el valor es no nulo y el controlador correctamente reemplazará y mostrar el menú cuando el controlador ejecuta una segunda vez.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. Esto sugiere dos posibles soluciones:This suggests two possible workarounds:

  1. Asegurarse de que ContextMenuOpening controladores siempre se ejecutan en los controles que tienen al menos un marcador de posición ContextMenu disponibles, que se va a reemplazarse por el código del controlador.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. En este caso, todavía puede usar el controlador que se muestra en el ejemplo anterior, pero normalmente desea asignar un marcador de posición ContextMenu en el marcado inicial: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. Suponga que la inicial ContextMenu valor puede ser null, según una lógica preliminar.Assume that the initial ContextMenu value might be null, based on some preliminary logic. Puede comprobar la ContextMenu para null, o usar una marca en el código para comprobar si el controlador ha sido ejecutar al menos una vez.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. Dado que se asume que el ContextMenu consiste en ser su controlador muestra a continuación, establece Handled a true en los datos del evento.Because you assume that the ContextMenu is about to be displayed, your handler then sets Handled to true in the event data. Para el ContextMenuService que es responsable de la presentación del menú contextual, un true valor Handled en el evento datos representan una solicitud para cancelar la presentación del menú contextual / control de combinación que provocó el 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.

Ahora que ha suprimido el menú contextual potencialmente sospechosos, el siguiente paso es proporcionar una nueva, a continuación, volver a mostrarlo.Now that you have suppressed the potentially suspect context menu, the next step is to supply a new one, then display it. Establecer el nuevo es básicamente el mismo que el controlador anterior: crear un nuevo ContextMenu y establezca el origen de control FrameworkElement.ContextMenu propiedad con ella.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. El paso adicional es que ahora debe forzar la presentación del menú contextual, porque se ha suprimido el primer intento.The additional step is that you must now force the display of the context menu, because you suppressed the first attempt. Para forzar la presentación, se establece la Popup.IsOpen propiedad true dentro del controlador.To force the display, you set the Popup.IsOpen property to true within the handler. Tenga cuidado al hacerlo, porque provoca abriendo el menú contextual en el controlador de la ContextMenuOpening nuevo evento.Be careful when you do this, because opening the context menu in the handler raises the ContextMenuOpening event again. Si volver a escribir el controlador, vuelve infinitamente recursivo.If you reenter your handler, it becomes infinitely recursive. Por eso siempre debe comprobar null o usar una marca si abre un menú contextual desde una ContextMenuOpening controlador de eventos.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.

Suprimir cualquier menú contextual existente y no mostrar ningún menú contextualSuppressing Any Existing Context Menu and Displaying No Context Menu

El último escenario, escribir un controlador que suprime un menú totalmente, es poco habitual.The final scenario, writing a handler that suppresses a menu totally, is uncommon. Si un control determinado no está pensado para mostrar un menú contextual, hay maneras probablemente más adecuado para garantizar que suprimir el menú sólo cuando un usuario lo solicita.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. Pero si desea usar el controlador para suprimir un menú contextual y mostrar nada, simplemente debe establecer el controlador Handled a true en los datos del 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. El ContextMenuService que es responsable de mostrar un menú contextual comprobará los datos del evento del evento produce en el control.The ContextMenuService that is responsible for displaying a context menu will check the event data of the event it raised on the control. Si se ha marcado el evento Handled en cualquier lugar a lo largo de la ruta, a continuación, la acción Abrir del menú contextual que inició el evento se ha suprimido.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;
        }
    }
}

Vea tambiénSee also