J'ai du mal à trouver comment définir le DataContext
correct sur un ContextMenu
.
J'ai une collection de modèles de vues qui sont la source d'un ItemsControl
. Chaque modèle de vue possède une collection d'éléments qui sont également la source d'un autre ItemsControl
. Chaque élément est utilisé pour dessiner une image qui a un ContextMenu
. Le MenuItems
dans ce ContextMenu
doit se lier à une commande sur le modèle de vue, mais le PlacementTarget
du ContextMenu
pointe vers l'élément individuel.
Mon Xaml ressemble à ceci:
<ItemsControl ItemsSource="{Binding Markers"}>
<ItemsControl.ItemTemplate>
<DataTemplate>
<ItemsControl ItemsSource="{Binding Items}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Image>
<Image.ContextMenu>
<ContextMenu>
<MenuItem Header="Edit" Command="{Binding EditCommand}" />
</ContextMenu>
</Image.ContextMenu>
</Image>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Comment puis-je définir le DataContext
du ContextMenu
sur le modèle de vue parent correspondant de l'élément?
Le ContextMenu est en dehors de l'arborescence visuelle. Voici le xaml qui devrait vous fournir le contexte de données:
<ItemsControl ItemsSource="{Binding Markers}" Tag="{Binding ElementName=outerControl, Path=DataContext}">
...
<ContextMenu DataContext="{Binding Path=PlacementTarget.Tag, RelativeSource={RelativeSource Self}}">
<MenuItem Header="Edit"
Command="{Binding EditCommand}" />
</ContextMenu>
...
</ItemsControl>
Ce post explique comment cela fonctionne.
Vous pouvez utiliser une extension de balisage:
using System;
using System.Windows.Controls;
using System.Windows.Markup;
using System.Xaml;
[MarkupExtensionReturnType(typeof(ContentControl))]
public class RootObject : MarkupExtension
{
public override object ProvideValue(IServiceProvider serviceProvider)
{
var rootObjectProvider = (IRootObjectProvider)serviceProvider.GetService(typeof(IRootObjectProvider));
return rootObjectProvider?.RootObject;
}
}
Il vous permet de faire:
<ItemsControl ItemsSource="{Binding Markers}">
...
<ContextMenu DataContext="{Binding DataContext, Source={local:RootObject}}">
<MenuItem Header="Edit"
Command="{Binding EditCommand}" />
</ContextMenu>
...
</ItemsControl>
Je n'aime pas utiliser Tag. Je préfère la propriété attenante.
Vous devez ajouter une propriété jointe:
public static readonly DependencyProperty DataContextExProperty = DependencyProperty.RegisterAttached("DataContextEx", typeof(Object), typeof(DependencyObjectAttached));
public static Object GetDataContextEx(DependencyObject element)
{
return element.GetValue(DataContextExProperty);
}
public static void SetDataContextEx(DependencyObject element, Object value)
{
element.SetValue(DataContextExProperty, value);
}
En XAML:
<Button attached:DependencyObjectAttached.DataContextEx="{Binding ElementName=MyDataContextElement, Path=DataContext}">
<Button.ContextMenu>
<ContextMenu DataContext="{Binding RelativeSource={RelativeSource Self}, Path=PlacementTarget.(attached:DependencyObjectAttached.DataContextEx)}">
</ContextMenu>
</Button.ContextMenu>
</Button>