Search code examples
wpfmvvmdatagridcontextmenudatacontext

Setting DataGrid and ContextMenu with Same DataContext


I am trying to dynamically create a Context Menu for a data grid that passes in the selected menu item (Mvvm). I want the DataContext to be the same for the for the context menu as the grid.

I have the following Xaml

<Grid>
  <!-- Cut some other stuff -->
  <Border Grid.Row="2" BorderBrush="Black" BorderThickness="1">
    <DataGrid x:Name="MyDataGrid" IsSynchronizedWithCurrentItem="True" ItemsSource="{Binding Path=GridData}" AutoGenerateColumns="False" IsReadOnly="True" GridLinesVisibility="None" SelectionUnit="Cell" SelectionMode="Single">
      <DataGrid.ContextMenu>
        <ContextMenu ItemsSource="{Binding ContextMenuActions}">
          <MenuItem Header="{Binding DisplayName}" Command="{Binding Command}" />
        </ContextMenu>
      </DataGrid.ContextMenu>
      <DataGrid.Columns>
        <DataGridTextColumn  Header="DataOne" Width="130" Binding="{Binding Path=DataOne}"/>
        <DataGridTextColumn  Header="DataTwo"   Width="100" Binding="{Binding Path=DataTwo}"/>
      <DataGrid.Columns>
      <DataGrid.InputBindings>
        <MouseBinding Gesture="RightClick"  Command="{Binding DataGridRightClick}" CommandParameter="{Binding ElementName=MyDataGrid, Path=SelectedCells}" />
      </DataGrid.InputBindings>
    </DataGrid>
  </Border>
</Grid> 

and the following classes for my data context that I use for my datagrid and would also like to use for my context menu (I have cut out all the data grid population code for readability ) and menuitems

public class DataViewModel : ViewModelBase // Implements INotifyPropertyChanged
{
    // All code that populates the grid has been removed

    public ObservableCollection<MenuItemViewModel> ContextMenuActions { get; set; }
    public ICommand DataGridRightClick { get; private set; }

    public MarketDataViewModel()
    {
        DataGridRightClick = new RelayCommand(RightClick);
    }

    public void RightClick(object obj)
    {
        MenuItemViewModel menuItem = new MenuItemViewModel("Test", new RelayCommand(TestCall));
        ContextMenuActions.Add(menuItem); // I ensure this is added on the gui thread
        MenuItemViewModel menuItem1 = new MenuItemViewModel("Test2", new RelayCommand(TestCall));
        ContextMenuActions.Add(menuItem1); // I ensure this is added on the gui thread but for 
    }

    private void TestCall(object obj)
    {
        // want to pass in the selected menuitem
    }
}

public class MenuItemViewModel 
{
    public MenuItemViewModel(string displayName,ICommand command)
    {
        DisplayName = displayName;
        Command = command;
    }

    public string DisplayName { get; set; }
    public ICommand Command { get; set; }
}

Currently when I click on the datagrid the right click event gets called and runs fine but an empty context menu appears on the grid.

Thanks, Nick


Solution

  • You need to bind to the DataContext.ContextMenuActions of the parent DataGrid. The easiest way to achieve this is by using the following binding:

    <ContextMenu ItemsSource="{Binding DataContext.ContextMenuActions, ElementName=MyDataGrid}" ...