I am new in WPF programming with MVVM pattern. Now I have added the context menu in the datagrid. But, when I click the right mouse button, I don\'t know how to get the sele
bigworld12 has close to the right answer here, but it breaks if your context menu is templated. Try:
DataGridRow row =
((sender as MenuItem)?.GetAncestors()
?.FirstOrDefault(dpo => dpo.GetType() == typeof(ContextMenu)) as ContextMenu)
?.PlacementTarget as DataGridRow;
for the code-behind. I used nullable operators in case you somehow get here without the expected parent tree and target (maybe by triggering the context menu while off the grid.)
I know this is an old question, but i wanted to share this very easy solution.
XAML:
<ContextMenu x:Key="MyRowMenu1" DataContext="{Binding PlacementTarget, RelativeSource={RelativeSource Self}}">
<MenuItem Click="MenuItem_Click" Header="Add to Favourites"/>
<MenuItem Header="Copy" >
<MenuItem Header="Copy Name"/>
<MenuItem Header="Copy ID" />
<MenuItem Header="Copy IP Affffdress"/>
</MenuItem>
</ContextMenu>
Code behind:
Private Sub MenuItem_Click(sender As Object, e As RoutedEventArgs)
Dim row As DataGridRow = DirectCast(DirectCast(DirectCast(sender, MenuItem).GetParentObject, ContextMenu).PlacementTarget, DataGridRow)
'replace with what ever item you want
Dim srvr As Server = DirectCast(row.Item, Server)
End Sub
This is a common problem in WPF. The solution is to utilise a Tag
property in the item DataTemplate
to hold the data item. First, let's add this part:
<DataTemplate DataType="{x:Type YourDataTypeXmlNamespace:YourDataType}">
<Border Tag="{Binding DataContext, RelativeSource={RelativeSource AncestorType={
x:Type YourViewsXmlNamespace:YourViewWhereThisIsDeclared}}}">
...
</Border>
</DataTemplate>
Now that we have access to the DataContext
of the UserControl
which can be found in the Tag
property of each data object, let's bind to this from the ContextMenu
... we do it using a handy property called PlacementTarget
:
<ContextMenu DataContext="{Binding PlacementTarget.Tag, RelativeSource={
RelativeSource Self}}">
<MenuItem Header="Do Something" Command="{Binding YourCommandInYourViewModel}"
CommandParameter="{Binding YourCollection.CurrentItem}">
...
</MenuItem>
</ContextMenu>
One thing to note is the YourCollection.CurrentItem
property shown in the CommandParameter
above. The CurrentItem
property is a property that I added into my collection classes to bind to the SelectedItem
properties of collection controls in the UI. If you don't have one of these, it's ok, but you will need a property that is bound to the SelectedItem
property of your collection control for this to work. For my example, I have this:
<ListBox ItemsSource="{Binding YourCollection}" SelectedItem="{Binding
YourCollection.CurrentItem}" />
Expanding on Bolu's comment you could use SelectedItem
to get the current item. Below is a quick example:
<DataGrid ItemsSource="{Binding Source}" SelectedItem="{Binding SelectedItemProperty, Mode=TwoWay}">
<DataGrid.ContextMenu>
<ContextMenu>
<MenuItem Command="{Binding MyCommand}" Header="MyCommand"/>
</ContextMenu>
</DataGrid.ContextMenu>
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Binding="{Binding Key, Mode=TwoWay}" Width="1*"/>
<DataGridTextColumn Header="Value" Binding="{Binding Value, Mode=TwoWay}" Width="3*"/>
</DataGrid.Columns>
</DataGrid>
SelectedItem
is now bound to SelectedItemProperty
in the ViewModel.
I think this is a similar case. I fixed it that way:
<ContextMenu x:Key="rowContextMenu" Background="Transparent" >
<MenuItem Header="{StaticResource LowPriority}" Style="{StaticResource menuStyle}"
CommandParameter="1" Click="ChangePriority"/>
</ContextMenu>
C# Code:
private async void ChangePriority(object sender, RoutedEventArgs a)
{
MyTypeInRow row = (MyTypeInRow)(((MenuItem)sender).DataContext);
...
}
DataGrid.ItemsSource contains ObservableCollection<MyTypeInRow>.