Create contextmenus for datagrid rows Create contextmenus for datagrid rows wpf wpf

Create contextmenus for datagrid rows


As far as I know, some of the actions will be disabled or enabled depending on the row, so there is no point in a single ContextMenu for a DataGrid.

I have an example of the row-level context menu.

<UserControl.Resources>    <ContextMenu  x:Key="RowMenu" DataContext="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}">        <MenuItem Header="Edit" Command="{Binding EditCommand}"/>    </ContextMenu>    <Style x:Key="DefaultRowStyle" TargetType="{x:Type DataGridRow}">        <Setter Property="ContextMenu" Value="{StaticResource RowMenu}" />    </Style></UserControl.Resources><DataGrid RowStyle="{StaticResource DefaultRowStyle}"/>

The DataGrid must have a binding to a list of view models with commands:

public class ItemModel{    public ItemModel()    {        this.EditCommand = new SimpleCommand         {             ExecuteDelegate = _ => MessageBox.Show("Execute"),             CanExecuteDelegate = _ => this.Id == 1         };    }    public int Id { get; set; }    public string Title { get; set; }    public ICommand EditCommand { get; set; }}

The context menu is created in the resources collection of the UserControl and I think there is only one object which is connected with datagrid rows by reference, not by value.

Here is another example of ContextMenu for a Command inside a MainViewModel. I suppose that DataGrid has a correct view model as the DataContext, also the CommandParameter attribute must be placed before the Command attribute:

    <ContextMenu  x:Key="RowMenu" DataContext="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}">        <MenuItem Header="Edit" CommandParameter="{Binding}"                  Command="{Binding DataContext.DataGridActionCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=DataGrid}}" />    </ContextMenu>

Models:

public class MainViewModel{    public MainViewModel()    {        this.DataGridActionCommand = new DelegateCommand<ItemModel>(m => MessageBox.Show(m.Title), m => m != null && m.Id != 2);    }    public DelegateCommand<ItemModel> DataGridActionCommand { get; set; }    public List<ItemModel> Items { get; set; }}public class ItemModel{    public int Id { get; set; }    public string Title { get; set; }}

But there is a problem that MenuItem isn't displayed as a disabled item if CanExecute returns false. The possible workaround is using a ParentModel property inside the ItemModel, but it doesn't differ much from the first solution.Here is example of above-described solution:

public class ItemModel{    public int Id { get; set; }    public string Title { get; set; }    public MainViewModel ParentViewModel { get; set; }}//Somewhere in the code-behind, create the main view model //and force child items to use this model as a parent modelvar mainModel = new MainViewModel { Items = items.Select(item => new ItemViewModel(item, mainModel)).ToList()};

And MenuItem in XAML will be simplier:

<MenuItem Header="Edit" CommandParameter="{Binding}"              Command="{Binding ParentViewModel.DataGridActionCommand}" />