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; }
}
}