views:

1149

answers:

2

Hello,

I'm trying to add a context menu to a column in the WPF datagrid and don't quite see how this is possible. I know how to add one to the datagrid, but I would like to have different menu items based on the column as well have the menu click event be aware of column or better yet the cell that the context menu was choosen for.

My ultimate goal is to create a context menu that has a "Clear" menu item which will be used to null out the data in that column. I don't want empty string or false in the case of a check box column, I want the underlying data to be nulled out. If anyone has a suggestion on a reusable way to do this that would be much appreciated as well.

Thanks much!

A: 

i add a context menu to the cells like this

  <!--Cell ContextMenu-->
  <ContextMenu
     x:Key="cellContextMenu">
     <MenuItem
        x:Name="menuFillUp"
        Click="menuFillUp_Click"
        Header="Fill _Up" />
     <MenuItem
        x:Name="menuFillDown"
        Click="menuFillDown_Click"
        Header="Fill _Down" />
  </ContextMenu>

and set it as so

  <!--DataCell Style - Adds ContextMenu-->
  <Style
     TargetType="{x:Type dg:DataGridCell}">
     <Setter
        Property="ContextMenu"
        Value="{DynamicResource cellContextMenu}" />
  </Style>

then i add a context menu to the column header using the following context menu

  <!--Show Hidden Columns ContextMenu-->
  <DataTemplate
     x:Key="menuItemColumnShow">
     <MenuItem
        x:Name="menuShowColumn"
        DataContext="{Binding Path=.}"
        Header="{Binding Path=Tag.Code}"
        Click="menuShowColumn_Click" />
  </DataTemplate>

  <!--Column ContextMenu-->
  <ContextMenu
     x:Key="columnContextMenu">
     <MenuItem
        x:Name="menuHideColumn"
        Click="menuHideColumn_Click"
        Header="Hide _Column" />
     <MenuItem
        x:Name="showMenu"
        Header="Show"
        ItemsSource="{Binding RelativeSource={RelativeSource AncestorType={x:Type local:ResultEditorGrid}}, Path=HiddenColumnCollection}"
        ItemTemplate="{StaticResource menuItemColumnShow}">
        <MenuItem.Style>
           <Style
              BasedOn="{StaticResource {x:Type MenuItem}}"
              TargetType="{x:Type MenuItem}">
              <Style.Triggers>
                 <DataTrigger
                    Binding="{Binding RelativeSource={RelativeSource self}, Path=Items.Count}"
                    Value="0">
                    <Setter
                       Property="Visibility"
                       Value="Collapsed" />
                 </DataTrigger>
              </Style.Triggers>
           </Style>
        </MenuItem.Style>
     </MenuItem>

     <MenuItem
        Header="_Add  Item"
        Command="local:MyCommands.AddTItem"
        CommandTarget="{Binding Path=PlacementTarget, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ContextMenu}}}" />
  </ContextMenu>

      <!--ColumnManagerCell Style - Adds ContextMenu - Tool Tip Style for Marking Scheme Preview-->
  <Style
     TargetType="{x:Type dg:DataGridColumnHeader}">

     <Setter
        Property="ContextMenu"
        Value="{DynamicResource columnContextMenu}" />
  </Style>

(im using a wierd mix of commands and click events, the code kind of evolved :) what the above code does is give me dynamic menus on the column headers. i have a hidden column collection on my derived grid, and i show shich columns are hidden/shown in the context menu on the column, and i have a seperate context menu for the cells in the grid.

you can find which column was clicked on by

 private void menuHideColumn_Click(object sender, RoutedEventArgs e) {

     //move thru the visual tree to get the context menu
     DependencyObject dep = (DependencyObject)e.OriginalSource;
     while ((dep != null) && !(dep is ContextMenu)) {
        dep = VisualTreeHelper.GetParent(dep);
     }
     if (dep == null) { }
     else {
        //we have a context menu, cast it
        ContextMenu contextMenu = (ContextMenu)dep;
        if (contextMenu.PlacementTarget is DataGridColumnHeader) {
           DataGridColumnHeader header = contextMenu.PlacementTarget as DataGridColumnHeader;
           //get the grid to hide the column
           myDerivedGrid.HideColumn(header.Column);
        }
     }
  }

i may have missed a few things, feel free to make a comment and ill try to fill in the detail.

Aran Mulholland
A: 

Another option is to set the column headers to a TextBlock (or some other control that can handle a context menu).

So you could say:

// Create a context menu var cm = new ContextMenu(); cm.Items.Add(new MenutItem{Header="SampleItem"});

// Create a textblock with your header text and link the context menu var tb = new TextBlock{Text="My Column Name"}; tb.ContextMenu = cm;

// Set the grid column header to your textblock grid.Columns[0].Header=tb;

Adam Taub