数据网格 wpf 的特定动态列的上下文菜单



>我真的需要帮助来弄清楚如何为数据网格上的特定列添加上下文菜单。

目前,我的数据网格如下所示:Datagrid和所有列都使用itemsource动态添加到数据网格中:ItemsSource="{Binding Data.DefaultView}"并且我有AutoGenerateColumns="True"。目前,我可以使用样式和触发器为所有标题添加不同的上下文菜单。例:

<Style TargetType="{x:Type DataGridColumnHeader}">
<Style.Triggers>
<Trigger Property="Content" Value="CoreRefDes">
<Setter Property="ContextMenu"
Value="{StaticResource DataGridColumnHeaderContextMenuSpecific}" />
</Trigger>
<Trigger Property="Content" Value="CorePartNumber">
<Setter Property="ContextMenu"
Value="{StaticResource DataGridColumnHeaderContextMenuSpecific}" />
</Trigger>
<Trigger Property="Content" Value="CoreDescription">
<Setter Property="ContextMenu"
Value="{StaticResource DataGridColumnHeaderContextMenuSpecific}" />
</Trigger>
<Trigger Property="Content" Value="Split">
<Setter Property="ContextMenu"
Value="{StaticResource DataGridColumnHeaderContextMenuSpecific}" />
</Trigger>
</Style.Triggers>

我想要类似的东西,但不是标题上的上下文菜单,而是我希望它位于单元格或基于标题名称的数据网格上。目前,我的上下文菜单显示在数据网格上,如下所示:

<Style TargetType="{x:Type DataGrid}">
<Setter Property="ContextMenu" Value="{DynamicResource DatagridCellContextmenuItems}"/>
</Style>

问题是我为所有列获得相同的上下文菜单。我想要第 1 列和第 2 列的不同上下文菜单。关于如何解决这个问题的任何想法?

谢谢!

实现这个有点痛苦,但这就是我过去所做的。

我在数据网格上有一个上下文菜单,其中包含我可能需要的每个可能的菜单项。然后,我根据单击的行/列/单元格隐藏或显示每个行/列/单元格。

下面是数据网格 XAML 代码段:

<DataGrid ContextMenuOpening="GridContextMenuOpening" ...>
<DataGrid.ContextMenu>
<ContextMenu>
<MenuItem x:Name="mnuOpen" ... />
<MenuItem x:Name="mnuNew" ... />
<!-- and so on -->
</ContextMenu>
</DataGrid.ContextMenu>
<!-- rest of datagrid - columns etc -->
</DataGrid>     

请注意 DataGrid 的 ContextMenuOpen 事件处理程序 - 下面是代码隐藏:-

private void GridContextMenuOpening(object sender, ContextMenuEventArgs e)
{
DataGridCell cell;
DataGridRow row;
var dep = DataGridMiscHelpers.FindVisualParentAsDataGridSubComponent(
(DependencyObject)e.OriginalSource);
if (dep == null)
{
return;
}
DataGridMiscHelpers.FindCellAndRow(dep, out cell, out row);
if (dep is DataGridColumnHeader || dep is DataGridRow)
{
e.Handled = true;
return;
}
// Hide/show the menu items depending on the cell and/or row clicked.
// (You could programmatically add/remove menu items here instead).
mnuOpen.Visibility = (cell.Column.Header == "whatever") ? Visibility.Hidden : Visibility.Visible;
mnuNew.Visibility = ((row.Item as MyViewModel).SomeProperty == 123) ? Visibility.Hidden : Visibility.Visible;
}

这是我的"DataGridMiscHelpers"静态类,上面代码使用:

using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Media;
using System.Windows.Media.Media3D;
public static class DataGridMiscHelpers
{
/// <summary>
/// Finds the visual parent of the given object
/// </summary>
/// <param name="originalSource">The original source.</param>
/// <returns></returns>
public static DependencyObject FindVisualParentAsDataGridSubComponent(
DependencyObject originalSource)
{
// iteratively traverse the visual tree
while ((originalSource != null) 
&& !(originalSource is DataGridCell) 
&& !(originalSource is DataGridColumnHeader) 
&& !(originalSource is DataGridRow))
{
if (originalSource is Visual || originalSource is Visual3D)
{
originalSource = VisualTreeHelper.GetParent(originalSource);
}
else
{
// If we're in Logical Land then we must walk 
// up the logical tree until we find a 
// Visual/Visual3D to get us back to Visual Land.
originalSource = LogicalTreeHelper.GetParent(originalSource);
}
}
return originalSource;
}
/// <summary>
/// Finds the cell and row data for the given source.
/// </summary>
/// <param name="originalSource">The original source.</param>
/// <param name="cell">The cell.</param>
/// <param name="row">The row.</param>
public static void FindCellAndRow(DependencyObject originalSource, 
out DataGridCell cell, out DataGridRow row)
{
cell = originalSource as DataGridCell;
if (cell == null)
{
row = null;
return;
}
// Walk the visual tree to find the cell's parent row.
while ((originalSource != null) && !(originalSource is DataGridRow))
{
if (originalSource is Visual || originalSource is Visual3D)
{
originalSource = VisualTreeHelper.GetParent(originalSource);
}
else
{
// If we're in Logical Land then we must walk up the logical tree 
// until we find a Visual/Visual3D to get us back to Visual Land.
// See: http://www.codeproject.com/Articles/21495/Understanding-the-Visual-Tree-and-Logical-Tree-in
originalSource = LogicalTreeHelper.GetParent(originalSource);
}
}
row = originalSource as DataGridRow;
}
}

}

免责声明:我刚刚从更大的代码库中复制/粘贴了其中一些片段,因此它可能不是 100% 正确的,但希望足以让您入门。

1(更改您的样式目标 yoDataGridCell

2( 列的每个数据触发器都将包含一个多重绑定。转换器将返回列标题。灵感在这里 IMultiValueConverter

2.a(您需要提供给转换器的值是该单元格的列标题内容。您正在寻找的装订类型的灵感

<CheckBox IsChecked="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type dg:DataGridColumnHeader}}, Path=Column.CellStyle, Mode=OneWayToSource, Converter={StaticResource CellBackgroundConverter}}" Content="Highlight Cells"/>

最新更新