How can I add a Click Event Handler to a DataGrid Context Menu?

Stout 286 Reputation points
2020-09-23T00:24:04.593+00:00

Hi. How can I add a Click Event Handler to a DataGrid's dynamically-generated ContextMenu?

I see people say use the 'Tag' attribute, but I'm not sure how to add the code in XAML, or whether that needs to be done in the code-behind.

Thanks.

<DataGrid ItemsSource="{Binding MyModules}" AutoGenerateColumns="False" x:Name="dataGrid">

    <DataGrid.ItemContainerStyle>
        <Style TargetType="DataGridRow">
            <Setter Property="ContextMenu">
                <Setter.Value>
                    <ContextMenu ItemsSource="{Binding Configuration.Commands}">
                        <ContextMenu.ItemContainerStyle>
                            <Style TargetType="MenuItem">
                                <Setter Property="Header" Value="{Binding Caption}" />
                                <!-- Instead of the following two lines where I set the CommandAction and CommandParameter, I need to have a Click Event Handler. How can I achieve that? -->
                                <!-- <Setter Property="Command" Value="{Binding CommandAction}" />
                                <Setter Property="CommandParameter" Value="{Binding CommandId}" /> -->
                            </Style>
                        </ContextMenu.ItemContainerStyle>
                    </ContextMenu>
                </Setter.Value>
            </Setter>
        </Style>
    </DataGrid.ItemContainerStyle>

    <DataGrid.Columns>
        <DataGridTemplateColumn Header="Module Name" Width="*" IsReadOnly="True">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding Configuration.Name}" />
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>

        <DataGridTemplateColumn Header="Module Caption" Width="3*" IsReadOnly="True">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding Configuration.Description}" />
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
    </DataGrid.Columns>

</DataGrid>
Windows Presentation Foundation
Windows Presentation Foundation
A part of the .NET Framework that provides a unified programming model for building line-of-business desktop applications on Windows.
2,681 questions
0 comments No comments
{count} votes

Accepted answer
  1. DaisyTian-1203 11,616 Reputation points
    2020-09-23T07:52:50.107+00:00

    You can use EventSetter to add click event in the Style like:

    <EventSetter Event="Click" Handler="MenuItem_Click"></EventSetter>  
    

    or

    <EventSetter Event="Click" Handler="{Binding ClickEventCmd}"></EventSetter>  
     
    

    If the response is helpful, please click "Accept Answer" and upvote it.
    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

    0 comments No comments

2 additional answers

Sort by: Most helpful
  1. Peter Fleischer (former MVP) 19,231 Reputation points
    2020-09-23T08:11:11.463+00:00

    Hi,
    try following approach (ICommand implementation in ViewModel):

    <Window x:Class="WpfApp1.Window84"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:WpfApp84"
            mc:Ignorable="d"
            Title="MainWindow" Height="450" Width="800">
      <Window.Resources>
        <local:ViewModel x:Key="vm"/>
      </Window.Resources>
      <Grid DataContext="{StaticResource vm}">
        <DataGrid ItemsSource="{Binding MyModules}" AutoGenerateColumns="False">
          <DataGrid.Resources>
            <ContextMenu x:Key="RowMenu" ItemsSource="{Binding Configuration.Commands}" >
              <ContextMenu.ItemContainerStyle>
                <Style TargetType="MenuItem">
                  <Setter Property="Header" Value="{Binding Caption}" />
                  <Setter Property="Command" Value="{Binding Source={StaticResource vm}}" />
                  <Setter Property="CommandParameter" Value="{Binding}" />
                </Style>
              </ContextMenu.ItemContainerStyle>
            </ContextMenu>
          </DataGrid.Resources>
          <DataGrid.RowStyle>
            <Style TargetType="DataGridRow" >
              <Setter Property="ContextMenu" Value="{StaticResource RowMenu}" />
            </Style>
          </DataGrid.RowStyle>
          <DataGrid.Columns>
            <DataGridTemplateColumn Header="Module Name" Width="*" IsReadOnly="True">
              <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                  <TextBlock Text="{Binding Configuration.Name}" />
                </DataTemplate>
              </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>
            <DataGridTemplateColumn Header="Module Description" Width="3*" IsReadOnly="True">
              <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                  <TextBlock Text="{Binding Configuration.Description}" />
                </DataTemplate>
              </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>
          </DataGrid.Columns>
        </DataGrid>
      </Grid>
    </Window>
    

    and classes:

    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Windows;
    using System.Windows.Input;
    
    namespace WpfApp84
    {
      public class ViewModel : ICommand
      {
        public ViewModel() => LoadData();
        public ObservableCollection<IModule> MyModules { get; set; }
    
        private void LoadData()
        {
          Random rnd = new Random();
          this.MyModules = new ObservableCollection<IModule>();
          int id = 1;
          for (int i = 1; i < 10; i++)
          {
            List<Command> cmds = new List<Command>();
            Module m = new Module($"Name {i}", $"Description {i}", cmds);
            for (int k = 1; k < rnd.Next(3, 8); k++)
              cmds.Add(new Command() { Caption = $"Menu {id} (Name {i} - {k})", CommandId = id++,  Parent = m });
            this.MyModules.Add(m);
          }
        }
    
        public void Execute(object parameter) =>
          ((Command)parameter).Parent.ExecuteCommand((Command)parameter);
    
        public event EventHandler CanExecuteChanged;
        public bool CanExecute(object parameter) => true;
      }
    
      public class Module : IModule
      {
        public Module(string name, string description, List<Command> commands) =>
          this.Configuration = new Configuration(name, description, commands);
    
        public Configuration Configuration { get; }
    
        public void ExecuteCommand(Command command) =>
          MessageBox.Show($"Selected menu item id: {command.CommandId}");
      }
    
      public interface IModule
      {
        Configuration Configuration { get; }
        void ExecuteCommand(Command command);
      }
    
      public class Configuration
      {
        public Guid Id { get; private set; }
        public string Name { get; private set; }
        public string Description { get; private set; }
        public List<Command> Commands { get; set; } = new List<Command>();
    
        public Configuration(string name, string description, List<Command> commands)
        {
          Id = new Guid();
          Name = name;
          Description = description;
          Commands = commands;
        }
      }
    
      public class Command
      {
        public int CommandId { get; set; }
        public string Caption { get; set; }
        public Module Parent { get; set; }
      }
    }
    
    0 comments No comments

  2. Stout 286 Reputation points
    2020-09-23T16:26:24.31+00:00

    That you, guys. That's exactly what I needed.

    Appreciate your help.

    0 comments No comments