WPF ContextMenu woes: How do I set the DataContext of the ContextMenu?
The ContextMenu is outside of the visual tree. Below is the xaml that should get you the datacontext:
<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>
This post explains how this works.
I don't like use Tag. I prefer attached property.
You need add attached property:
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);
}
In 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>
You can use a markupextension:
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;
}
}
It lets you do:
<ItemsControl ItemsSource="{Binding Markers}">
...
<ContextMenu DataContext="{Binding DataContext, Source={local:RootObject}}">
<MenuItem Header="Edit"
Command="{Binding EditCommand}" />
</ContextMenu>
...
</ItemsControl>