Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
L’événement ContextMenuOpening peut être géré dans une application pour ajuster un menu contextuel existant avant l’affichage ou pour supprimer le menu qui serait autrement affiché en définissant la propriété Handled sur true dans les données d’événement. La raison classique de définir Handled à true dans les données d’événement consiste à remplacer entièrement le menu par un nouvel objet ContextMenu, ce qui nécessite parfois l’annulation de l’opération et le démarrage d’un nouvel objet ouvert. Si vous écrivez des gestionnaires pour l’événement ContextMenuOpening, vous devez connaître les problèmes de synchronisation entre un contrôle ContextMenu et le service responsable de l’ouverture et du positionnement des menus contextuels pour les contrôles en général. Cette rubrique illustre certaines des techniques de code pour différents scénarios d’ouverture de menu contextuel et illustre un cas où le problème de minutage entre en jeu.
Il existe plusieurs scénarios de gestion de l’événement ContextMenuOpening :
Ajustement des éléments de menu avant l’affichage.
Remplacement de l’intégralité du menu avant l’affichage.
Supprime complètement tout menu contextuel existant et n’affiche aucun menu contextuel.
Exemple :
Ajustement des éléments de menu avant l’affichage
L’ajustement des éléments de menu existants est assez simple et est probablement le scénario le plus courant. Vous pouvez le faire pour ajouter ou soustraire des options de menu contextuel en réponse aux informations d’état actuelles de votre application ou des informations d’état particulières disponibles sous forme de propriété sur l’objet où le menu contextuel est demandé.
La technique générale consiste à obtenir la source de l’événement, qui est le contrôle spécifique qui a été cliqué avec le bouton droit et à obtenir la propriété ContextMenu à partir de celle-ci. Vous souhaitez généralement vérifier la collection Items pour voir quels éléments de menu contextuel existent déjà dans le menu, puis ajouter ou supprimer les nouveaux éléments MenuItem appropriés à ou à partir de la 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);
}
Remplacement de l’intégralité du menu avant l’affichage
Un autre scénario consiste à remplacer l’intégralité du menu contextuel. Bien sûr, vous pouvez également utiliser une variante du code précédent, pour supprimer chaque élément d’un menu contextuel existant et en ajouter de nouveaux à partir de l’élément zéro. Mais l’approche plus intuitive pour remplacer tous les éléments du menu contextuel consiste à créer une nouvelle ContextMenu, à la remplir avec des éléments, puis à définir la propriété FrameworkElement.ContextMenu d’un contrôle comme étant la nouvelle ContextMenu.
Voici le code de gestionnaire simple pour remplacer un ContextMenu. Le code fait référence à une méthode personnalisée BuildMenu, qui est isolée car elle est appelée par plusieurs des gestionnaires d'exemple.
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;
}
Toutefois, si vous utilisez ce style de gestionnaire pour ContextMenuOpening, vous pouvez potentiellement exposer un problème de minutage si l’objet où vous définissez le ContextMenu n’a pas de menu contextuel préexistant. Lorsqu’un utilisateur clique avec le bouton droit sur un contrôle, ContextMenuOpening est déclenché même si le ContextMenu existant est vide ou null. Mais dans ce cas, quelle que soit la nouvelle valeur de ContextMenu que vous définissez sur l’élément source, elle arrive trop tard pour être affichée. En outre, si l'utilisateur clique avec le bouton droit pour la deuxième fois, cette fois, votre nouvelle ContextMenu s'affiche, la valeur n'est pas nulle et votre gestionnaire remplacera et affichera correctement le menu lors de son deuxième passage. Cela suggère deux solutions de contournement possibles :
Assurez-vous que les gestionnaires ContextMenuOpening s’exécutent toujours sur des contrôles qui disposent au moins d'un espace réservé ContextMenu, que vous avez l'intention de remplacer par le code du gestionnaire. Dans ce cas, vous pouvez toujours utiliser le gestionnaire indiqué dans l’exemple précédent, mais vous souhaitez généralement affecter un espace réservé ContextMenu dans le balisage initial :
<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>Supposons que la valeur initiale de ContextMenu peut être null, en fonction d’une logique préliminaire. Vous pouvez vérifier ContextMenu pour null ou utiliser un indicateur dans votre code pour vérifier si votre gestionnaire a été exécuté au moins une fois. Étant donné que vous supposez que le ContextMenu est sur le point d’être affiché, votre gestionnaire définit ensuite Handled sur
truedans les données d’événement. À l'ContextMenuService responsable de l’affichage du menu contextuel, une valeurtruepour Handled dans les données d’événement représente une demande d’annulation de l’affichage du menu contextuel/contrôle lié qui a déclenché l’événement.
Maintenant que vous avez supprimé le menu contextuel potentiellement suspect, l’étape suivante consiste à en fournir une nouvelle, puis à l’afficher. Définir le nouveau est essentiellement le même que le gestionnaire précédent : vous générez une nouvelle ContextMenu et définissez la propriété FrameworkElement.ContextMenu de la source de contrôle avec celle-ci. L’étape supplémentaire est que vous devez maintenant forcer l’affichage du menu contextuel, car vous avez supprimé la première tentative. Pour forcer l’affichage, vous définissez la propriété Popup.IsOpen sur true dans le gestionnaire. Soyez prudent lorsque vous effectuez cette opération, car l’ouverture du menu contextuel dans le gestionnaire déclenche à nouveau l’événement ContextMenuOpening. Si vous entrez à nouveau dans votre gestionnaire, celui-ci devient récursif à l’infini. C’est pourquoi vous devez toujours rechercher null ou utiliser un indicateur si vous ouvrez un menu contextuel à partir d’un gestionnaire d’événements ContextMenuOpening.
Suppression d’un menu contextuel existant et absence d’affichage de menu contextuel
Le scénario final, l’écriture d’un gestionnaire qui supprime totalement un menu, est rare. Si un contrôle donné n’est pas censé afficher un menu contextuel, il existe probablement des moyens plus appropriés d’assurer cela qu’en supprimant le menu juste quand un utilisateur le demande. Toutefois, si vous souhaitez utiliser le gestionnaire pour supprimer un menu contextuel et ne rien afficher, votre gestionnaire doit simplement définir Handled sur true dans les données d’événement. Le ContextMenuService responsable de l’affichage d’un menu contextuel vérifie les données d’événement de l’événement déclenché sur le composant. Si l’événement a été marqué Handled n’importe où le long de l’itinéraire, alors l'action d'ouverture du menu contextuel qui a initié l'événement est supprimée.
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;
}
}
}
Voir aussi
- ContextMenu
- FrameworkElement.ContextMenu
- Vue d’ensemble des éléments de base
- Vue d’ensemble de ContextMenu
.NET Desktop feedback