我想通过右键单击列标题,通过用户可用的DataGrid
控制ContextMenu
列可见性。 ContextMenu
显示所有可用列的名称。我正在使用MVVM设计模式。
我的问题是:如何将DataGridColumn
的{{1}}属性绑定到位于Visibility
的{{1}}的{{1}}属性。< / p>
一些模型代码:
IsChecked
... flaf flaf flaf
MenuItem
如果我不清楚,请告诉我,我会尝试详细说明。
干杯,
答案 0 :(得分:18)
我刚刚写了一篇关于这个主题的博文。它允许通过右键单击任何列标题可访问的ContextMenu显示或隐藏DataGridColumns。此任务完全通过附加属性完成,因此它符合MVVM。
答案 1 :(得分:13)
我一直在寻找泛型, XAML (即没有代码隐藏),自动和简单列的示例选择器上下文菜单,绑定到WPF DataGrid列标题。我已经阅读了数百篇文章,但似乎没有一篇文章完全是正确的,或者它们不够通用。所以这就是我认为最好的组合解决方案:
首先,将它们放在资源字典中。我将把它作为练习留给读者编写可见性/布尔转换器,以确保复选框检查列何时可见,反之亦然。请注意,通过为上下文菜单资源定义x:Shared =“False”,它将获得特定于实例的状态,这意味着您可以将此单个模板/资源用于所有数据网格,并且它们都将保持自己的状态。
<Converters:VisiblityToInverseBooleanConverter x:Key="VisiblityToInverseBooleanConverter"/>
<ContextMenu x:Key="ColumnChooserMenu" x:Shared="False"
DataContext="{Binding Path=PlacementTarget, RelativeSource={RelativeSource Self}}"
ItemsSource="{Binding Columns, RelativeSource={RelativeSource AncestorType={x:Type sdk:DataGrid}}}">
<ContextMenu.ItemContainerStyle>
<Style TargetType="MenuItem">
<Setter Property="Header" Value="{Binding Header}"/>
<Setter Property="AutomationProperties.Name" Value="{Binding Header}"/>
<Setter Property="IsCheckable" Value="True" />
<Setter Property="IsChecked" Value="{Binding Visibility, Mode=TwoWay, Converter={StaticResource VisiblityToInverseBooleanConverter}}" />
</Style>
</ContextMenu.ItemContainerStyle>
</ContextMenu>
<Style x:Key="ColumnHeaderStyle" TargetType="{x:Type Primitives:DataGridColumnHeader}">
<Setter Property="ContextMenu" Value="{StaticResource ColumnChooserMenu}" />
</Style>
<ContextMenu x:Key="GridItemsContextMenu" >
<MenuItem Header="Launch Do Some other action"/>
</ContextMenu>
然后按如下方式定义DataGrid(其中OrdersQuery是View模型公开的一些数据源):
<sdk:DataGrid ItemsSource="{Binding OrdersQuery}"
AutoGenerateColumns="True"
ColumnHeaderStyle="{StaticResource ColumnHeaderStyle}"
ContextMenu="{StaticResource GridItemsContextMenu}">
<!-- rest of datagrid stuff goes here -->
</sdk:DataGrid>
这将为您提供以下内容:
希望这可以帮助那些一直在寻找这样一个例子的人。
答案 2 :(得分:6)
我知道这有点老了。但我正在考虑这样做,这篇文章更简单: http://iimaginec.wordpress.com/2011/07/25/binding-wpf-toolkit%E2%80%99s-datagridcolumn-to-a-viewmodel-datacontext-propogation-for-datagrid-columns-the-mvvm-way-to-interact-with-datagridcolumn/
您需要做的就是在列上设置DataContext,然后按照正常情况将Visibility绑定到ViewModel! :)简单有效
答案 3 :(得分:1)
好的,这对于WPF n00b来说已经很好了。
IanR感谢您提出的建议,我使用了类似的方法,但它总是带你去。
如果有人能找到更一致的方法,我会想出以下内容我会感激任何评论:
阻碍:
DataGridColumnHeader不支持上下文菜单。因此,上下文菜单需要作为样式应用。
contextmenu有自己的datacontext,所以我们必须使用findancestor将它链接到ViewModels datacontext。
ATM DataGrid控件不会将其datacontext解析为其Columns。这可以在代码隐藏中解决,但是我们使用MVVM模式,所以我决定遵循jamiers方法
解决方案:
将以下两个代码块放在Window.Resources
中 <Style x:Key="ColumnHeaderStyle"
TargetType="{x:Type toolkit:DataGridColumnHeader}">
<Setter Property="ContextMenu"
Value="{StaticResource ColumnHeaderContextMenu}" />
</Style>
<ContextMenu x:Key="ColumnHeaderContextMenu">
<MenuItem x:Name="MyMenuItem"
IsCheckable="True"
IsChecked="{Binding DataContext.IsHidden, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type toolkit:DataGrid}}}"/>
</ContextMenu>
然后,数据网格在XAML
中看起来像这样 <toolkit:DataGrid x:Name="MyGrid"
AutoGenerateColumns="False"
ItemsSource="{Binding SampleCollection, Mode=Default}"
EnableColumnVirtualization="True"
IsReadOnly="True"
ColumnHeaderStyle="{StaticResource ColumnHeaderStyle}">
<toolkit:DataGrid.Columns>
<toolkit:DataGridTextColumn Binding="{Binding Path=SamplingUser}"
Header="{Binding (FrameworkElement.DataContext).IsHidden, RelativeSource={x:Static RelativeSource.Self}}"
Visibility="{Binding (FrameworkElement.DataContext).IsHidden,
RelativeSource={x:Static RelativeSource.Self},
Converter={StaticResource booleanToVisibilityConverter}}"/>
因此,DataGridColumn和ischeked属性的visibility属性都被数据绑定到viewModel上的IsHidden属性。
在ViewModel中:
public bool IsHidden
{
get { return isHidden; }
set
{ if (value != isHidden)
{
isHidden = value;
OnPropertyChanged("IsHidden");
OnPropertyChanged("IsVisible");
}
}
}
Jaimer定义的Helper类:
class DataGridSupport
{
static DataGridSupport()
{
DependencyProperty dp = FrameworkElement.DataContextProperty.AddOwner(typeof(DataGridColumn));
FrameworkElement.DataContextProperty.OverrideMetadata ( typeof(DataGrid), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.Inherits, new PropertyChangedCallback(OnDataContextChanged)));
}
public static void OnDataContextChanged ( DependencyObject d, DependencyPropertyChangedEventArgs e)
{
DataGrid grid = d as DataGrid ;
if ( grid != null )
{
foreach ( DataGridColumn col in grid.Columns )
{
col.SetValue ( FrameworkElement.DataContextProperty, e.NewValue );
}
}
}
}
在viewmodel中显示(仅显示在实际项目中通过Unity完成)
private static DataGridSupport dc = new DataGridSupport();
干杯,
答案 4 :(得分:0)
您可以使用x:static
代替booleanToVisibilityConverter<Setter TargetName="UIElement" Property="UIElement.Visibility" Value="x:Static Visibility.Hidden" />
XAML中的静态: http://msdn.microsoft.com/en-us/library/ms742135.aspx
答案 5 :(得分:-1)
我确实尝试使用'ElementName'绑定到ContextMenu,但最后,使用VM中的属性使其工作,例如
bool _isHidden;
public bool IsHidden
{
get { return _isHidden; }
set
{
if (value != _isHidden)
{
_isHidden = value;
RaisePropertyChanged("IsHidden");
RaisePropertyChanged("IsVisible");
}
}
}
public Visibility IsVisible
{
get { return IsHidden ? Visibility.Hidden : Visibility.Visible; }
}
并在XAML中:
<Window.ContextMenu>
<ContextMenu>
<MenuItem Header="Hidden" IsCheckable="True" IsChecked="{Binding IsHidden}" />
</ContextMenu>
</Window.ContextMenu>
<toolkit:DataGrid x:Name="MyGrid" AutoGenerateColumns="False" ItemsSource="{Binding MyCollection, Mode=Default}" EnableColumnVirtualization="True" IsReadOnly="True" ColumnHeaderStyle="{StaticResource ColumnHeaderStyle}">
<toolkit:DataGrid.Columns>
<toolkit:DataGridTextColumn Binding="{Binding Path=MyEntry}" Header="MyEntry" Visibility="{Binding Path=IsVisible, Mode=OneWay}" />
</toolkit:DataGrid.Columns>
</toolkit:DataGrid>