I am using WPF and MVVM. I have a Window and a view model attached to it via Datacontext
. The window has a listbox
, and its items have context menu. I am using DelegateCommand
in my view model, and I want to bind a menu items in the context menu to this command.
The first problem is that by default the menu item is bound to the DataContext
of the list box item, which may or may not have knowledge of the whole view model.
The second problem is that context menu is not part of the visual tree, so referring to the main window via FindAncestor
or ElementName=...
will not work.
You can get to the object immediately containing the context menu via the PlacementTarget
property, but then you will need an ancestor of this object (“window
”), and there is no built-in way to find an ancestor of a property.
An (almost) working solution that I found on the Internet after hours of search was to store the data context some property of the PlacementTarget
– they used Tag
for this purpose.
The “almost” part lies in the fact that if your command has CanExecute()
method, the command parameter passed to it is sometimes null
(see here).
<Window Name="MainWindow" ...>
<Grid>
<ListBox ItemsSource="{Binding Items}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal"
Tag="{Binding DataContext, ElementName=MainWindow}">
...
<StackPanel.ContextMenu>
<MenuItem Header="do it"
Command="{Binding PlacementTarget.Tag.MyCommand,
RelativeSource={RelativeSource AncestorType=ContextMenu}}"
CommandParameter="{Binding}">
</StackPanel.ContextMenu>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Window>