<DataTemplate x:Key="_ItemTemplateA">
<Grid Tag="{Binding Path=DataContext.Command, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ContentControl Content="{Binding}" ContentTemplate="{StaticResource ContentTemplateB}" Grid.Row="0" />
<ContentControl Name="uiContentPresenter" Content="{Binding ContentView}" Grid.Row="1" Height="0" />
<ContentControl DataContext="{Binding IsContentDisplayed}" DataContextChanged="IsDisplayed_Changed" Visibility="Collapsed" />
<Grid.ContextMenu>
<ContextMenu>
<MenuItem Header="Text"
Command="{Binding Path=PlacementTarget.Tag, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ContextMenu}}}"
CommandParameter="{Binding}" />
</ContextMenu>
</Grid.ContextMenu>
</Grid>
</DataTemplate>
The above data template is applied to an ItemsControl. The issue is that for the ContextMenu that is specified for the Grid, the PlacementTarget property is never actually getting set to anything so I cannot get to the Tag property of the Grid which is necessary for passing the Command that should execute on the parent UserControl down to the context menu. I've based this approach off of similar examples such as this: http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/0244fbb0-fd5f-4a03-bd7b-978d7cbe1be3/
I've not been able to identify any other good way to pass this command down. This is setup this way because we are using an MVVM approach so the command we have to execute lives in the View Model of the user control this template is applied in. I've tried explicitly setting the PlacementTarget in a few different ways but it still always shows up as not set.
I realise that this is old and answered, but it doesn't seem properly answered. I came across a similar post and left a full answer. You might like to take a look as you can get it working with just a few adjustments to your code.
First, name your view
UserControl
... I generally name all of mineThis
for simplicity. Then remembering that our view model is bound to theDataContext
of theUserControl
, we can bind to the view model using{Binding DataContext, ElementName=This}
.So now we can bind to the view model, we have to connect that with the
ContextMenu.DataContext
. I use theTag
property of the object with theContextMenu
(thePlacementTarget
) as that connection, in this example, aGrid
:We can then access the view model properties and commands in the
ContextMenu
by binding theContextMenu.DataContext
property to thePlacementTarget.Tag
property (of theGrid
in our example):Note the binding on the
MenuItem.CommandTarget
property. Setting this ensures that the target element on which the specified command is raised is thePlacementTarget
, or theGrid
in this case.Also note the
CommandParameter
binding. This binds to theDataContext
of thePlacementTarget
, or theGrid
in this case. TheDataContext
of theGrid
will be inherited from theDataTemplate
and so your data item is now bound to theobject
parameter in yourCommand
if you're using some implementation of theICommand
interface:Or if you are using some kind of
RelayCommand
delegates directly in your view model:Here is a working standalone XAML-only example based on your test case: a
ContextMenu
that retrieves aCommand
from theDataContext
of itsPlacementTarget
using aTag
. You can reintroduce portions of your code until it stops working to try to find where the problem is:We have the same problem, but it works randomly. A contextmenu inside the controltemplate in a style for a listbox. We have tried to move the contextmenu to different levels inside the template but the same error occurs.
We think it might be connected to the refreshing of our ICollectionView that is the itemssource of the ListBox.
It seems that when the view refreshes the relative source binding inside the contextmenu is being evaluated before the PlacementTarget is being set.
It feels like a bug in either collectionviewsource or the ContextMenu of WPF...