Alors que vous pouvez créer un ControlTemplate pour le faire comme ils le font here, je suis d'accord qu'il est une méthode lourde juste pour modifier une valeur sur une partie des MenuItems. Au lieu de cela, je pense que c'est un bon endroit pour utiliser un AttachedProperty. Nous pouvons créer quelque chose comme le ContextMenuService, mais pour Popups (En fait, je suis un peu surpris qu'il ne soit pas intégré).
Pour changer l'endroit où le popup s'ouvre, nous allons vouloir définir le PlacementMode du Popup. Nous pouvons utiliser le raccourci propa pour générer notre AttachedProperty (ou les propriétés si vous voulez implémenter le reste). Nous devons ajouter un rappel à notre propriété PropertyMetadata, mais si la propriété AttachedProperty est définie en ligne sur le contrôle en XAML, le rappel se déclenchera avant que le contrôle entier ne soit entièrement construit. Pour assurer le modèle de MenuItem est appliqué, et le Popup existe avant d'essayer de régler sa valeur, nous pouvons simplement joindre à l'événement Loaded si elle est pas déjà chargé. Une fois qu'il est chargé, nous voulons récupérer le Popup à partir du modèle, et si nous regardons le MenuItem class nous pouvons voir qu'il a un TemplatePartAttribute définissant le nom du Popup comme « PART_Popup ». Une fois que nous avons cela, nous pouvons définir le PlacementMode sur le Popup MenuItem.
public static PlacementMode GetMenuPlacement(DependencyObject obj)
{
return (PlacementMode)obj.GetValue(MenuPlacementProperty);
}
public static void SetMenuPlacement(DependencyObject obj, PlacementMode value)
{
obj.SetValue(MenuPlacementProperty, value);
}
// Using a DependencyProperty as the backing store for MenuPlacement. This enables animation, styling, binding, etc...
public static readonly DependencyProperty MenuPlacementProperty =
DependencyProperty.RegisterAttached("MenuPlacement",
typeof(PlacementMode),
typeof(Window1),
new FrameworkPropertyMetadata(PlacementMode.Bottom, FrameworkPropertyMetadataOptions.Inherits, new PropertyChangedCallback(OnMenuPlacementChanged)));
private static void OnMenuPlacementChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
var menuItem = o as MenuItem;
if (menuItem != null)
{
if (menuItem.IsLoaded)
{
SetPopupPlacement(menuItem, (PlacementMode)e.NewValue);
}
else
{
menuItem.Loaded += new RoutedEventHandler((m, v) => SetPopupPlacement(menuItem, (PlacementMode)e.NewValue));
}
}
}
private static void SetPopupPlacement(MenuItem menuItem, PlacementMode placementMode)
{
Popup popup = menuItem.Template.FindName("PART_Popup", menuItem) as Popup;
if (popup != null)
{
popup.Placement = placementMode;
}
}
Maintenant que nous avons notre AttachedProperty, il est facile de changer la mise en place de Popup dans l'interface utilisateur.
<Menu>
<MenuItem Header="Item 1"
local:Window1.MenuPlacement="Right">
<MenuItem Header="SubItem 1" />
<MenuItem Header="SubItem 2" />
<MenuItem Header="SubItem 3" />
<MenuItem Header="SubItem 4" />
</MenuItem>
<MenuItem Header="Item 2"
local:Window1.MenuPlacement="Left">
<MenuItem Header="SubItem 5" />
<MenuItem Header="SubItem 6" />
<MenuItem Header="SubItem 7" />
<MenuItem Header="SubItem 8" />
</MenuItem>
<MenuItem Header="Item 3"
local:Window1.MenuPlacement="Mouse">
<MenuItem Header="SubItem 9" />
<MenuItem Header="SubItem 10" />
<MenuItem Header="SubItem 11" />
<MenuItem Header="SubItem 12" />
</MenuItem>
</Menu>
Merci. Cela ne l'affaire et j'aime la méthode générale utilisée ici et le code affiché est en fait un bon code de travail. Bonne réponse. –