Nota
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
El ContextMenuOpening evento se puede manejar en una aplicación para ajustar antes de mostrar un menú contextual existente o suprimir el menú que, de lo contrario, se mostraría estableciendo la propiedad Handled a true
en los datos del evento. La razón habitual para establecer Handled en true
en los datos del evento es reemplazar el menú por completo con un nuevo objeto ContextMenu, lo que a veces requiere cancelar la operación e iniciar una nueva apertura. Si escribe controladores para el ContextMenuOpening evento, debe tener en cuenta los problemas de tiempo entre un control ContextMenu y el servicio responsable de abrir y colocar menús contextuales para los controles en general. En este tema se muestran algunas de las técnicas de código para varios escenarios de apertura de menú contextual y se muestra un caso en el que entra en juego el problema de tiempo.
Hay varios escenarios para controlar el ContextMenuOpening evento:
Ajuste de los elementos de menú antes de mostrar.
Reemplazar todo el menú antes de mostrarlo.
Suprime completamente cualquier menú contextual existente y no muestra ningún menú contextual.
Ejemplo
Ajustar los elementos de menú antes de mostrar
Ajustar los elementos de menú existentes es bastante sencillo y probablemente es el escenario más común. Puede hacerlo para agregar o restar opciones de menú contextual en respuesta a la información de estado actual de la aplicación o información de estado determinada que está disponible como propiedad en el objeto donde se solicita el menú contextual.
La técnica general consiste en obtener el origen del evento, que es el control específico en el que se hizo clic con el botón derecho y obtener la ContextMenu propiedad de él. Normalmente, se recomienda comprobar la Items colección para ver qué elementos del menú contextual ya existen en el menú y, a continuación, agregar o quitar los nuevos elementos MenuItem adecuados en la colección.
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 todo el menú antes de mostrar
Un escenario alternativo es si desea reemplazar todo el menú contextual. Por supuesto, también podría usar una variación del código anterior, para quitar todos los elementos de un menú contextual existente y agregar otros nuevos a partir del elemento cero. Pero el enfoque más intuitivo para reemplazar todos los elementos del menú contextual es crear un nuevo ContextMenu, rellenarlo con elementos y, a continuación, establecer la FrameworkElement.ContextMenu propiedad de un control para que sea el nuevo ContextMenu.
A continuación se muestra el código de controlador sencillo para reemplazar un ContextMenu. El código hace referencia a un método personalizado BuildMenu
, el cual se ha separado porque lo llaman más de uno de los ejemplos de controladores.
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 exponer un problema de tiempo si el objeto en el que se establece ContextMenu no tiene un menú contextual preexistente. Cuando un usuario hace clic con el botón derecho en un control, ContextMenuOpening se genera incluso si el existente ContextMenu está vacío o es null. Pero en este caso, cualquier nuevo ajuste ContextMenu que establezca en el elemento de origen llega demasiado tarde para mostrarse. Además, si el usuario hace clic con el botón derecho en una segunda vez, esta vez aparece el nuevo ContextMenu , el valor no es NULL y el controlador reemplazará correctamente y mostrará el menú cuando el controlador se ejecute una segunda vez. Esto sugiere dos posibles soluciones alternativas:
Asegúrese de que los controladores ContextMenuOpening siempre se ejecuten para controles que tengan al menos un marcador de posición ContextMenu disponible, y que pretende reemplazar por el código del controlador. En este caso, puede seguir usando el controlador que se muestra en el ejemplo anterior, pero generalmente se prefiere asignar un marcador ContextMenu de posición en el marcado inicial.
<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>
Supongamos que el valor inicial ContextMenu podría ser NULL, en función de alguna lógica preliminar. Puede comprobar ContextMenu si hay valores NULL o usar una marca en el código para comprobar si el controlador se ha ejecutado al menos una vez. Dado que se supone que ContextMenu está a punto de mostrarse, el controlador entonces establece Handled en
true
dentro de los datos del evento. Para el ContextMenuService responsable de la presentación del menú contextual, un valortrue
para Handled en los datos del evento representa una solicitud para cancelar la presentación de la combinación de menú contextual y control que originó el evento.
Ahora que ha suprimido el menú contextual potencialmente sospechoso, el siguiente paso es proporcionar uno nuevo y, a continuación, mostrarlo. La configuración del nuevo es básicamente igual que el controlador anterior: se construye un nuevo ContextMenu y se establece la propiedad FrameworkElement.ContextMenu de la fuente de control con él. El paso adicional es que ahora debe forzar la visualización del menú contextual, ya que ha suprimido el primer intento. Para forzar la presentación, establezca la propiedad Popup.IsOpen a true
dentro del controlador. Tenga cuidado al hacerlo, ya que al abrir el menú contextual en el controlador se vuelve a generar el ContextMenuOpening evento. Si vuelve a ingresar el controlador, se vuelve infinitamente recursivo. Este es el motivo por el que siempre debe comprobar null
o usar una marca si abre un menú contextual desde dentro de un ContextMenuOpening controlador de eventos.
Suprimir cualquier menú contextual existente y no mostrar ninguno.
El escenario final, escribir un controlador que suprime totalmente un menú, es poco común. Si no se supone que un control determinado muestre un menú contextual, es probable que haya formas más adecuadas de asegurar esto que suprimir el menú justo cuando un usuario lo solicita. Pero si desea usar el controlador para suprimir un menú contextual y no mostrar nada, entonces su controlador simplemente debe establecer Handled en true
en los datos del evento. El ContextMenuService que es responsable de mostrar un menú contextual verificará los datos del evento que se activó en el control. Si el evento se marcó Handled en cualquier lugar de la ruta, se suprime la acción de apertura del menú contextual que inició el evento.
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;
}
}
}
Consulte también
.NET Desktop feedback