WPF DataGrid.Binding DataGridColumn可见性与ContextMenu MenuItems IsChecked (MVVM) 将DataGridColumn的可见性绑定到ContextMenu MenuItems的IsChecked(MVVM)

问题描述 投票:8回答:6

我想控制 DataGrid 列的可见性,通过 ContextMenu 用户可通过右键单击列头来获得。栏中的 ContextMenu 显示所有可用列的名称。我使用的是MVVM设计模式。

我的问题是:我如何绑定 DataGridColumn's Visibility 的属性,以 IsChecked 属于 MenuItem 位于 ContextMenu.

一些模拟代码。

<UserControl.Resources>         
    <ContextMenu x:Key="ColumnHeaderContextMenu">  
        <MenuItem Header="Menu Item..1" IsCheckable="True" />  
    </ContextMenu>  
    <Style x:Key="ColumnHeaderStyle" 
           TargetType="{x:Type toolkit:DataGridColumnHeader}">  
        <Setter Property="ContextMenu" 
                Value="{StaticResource ColumnHeaderContextMenu}" />  
    </Style>  
    <BooleanToVisibilityConverter x:Key="booleanToVisibilityConverter" />  
</UserControl.Resources>  

... flaf flaf

<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 IsChecked, Converter=
                {StaticResource booleanToVisibilityConverter}.... />
    </toolkit:DataGrid.Columns>     
</toolkit:DataGrid>  

如果我说的不清楚,请告诉我,我将尝试详细说明。

干杯。

wpf xaml mvvm datagrid binding
6个回答
19
投票

我刚刚写了一篇关于这个主题的博客文章。它允许DataGridColumns通过ContextMenu显示或隐藏,用户可以通过右键点击任何列头来访问。这个任务纯粹是通过附加的属性来完成的,所以它是符合MVVM的。

请看博客文章


15
投票

我一直在寻找一个 通用, XAML (即无编码),自动和。简单的 绑定到WPF DataGrid列头的列选择器上下文菜单的例子。我读了几百篇文章,但似乎没有一篇文章能做到这一点。恰恰 正确的东西,或者他们没有足够的通用性。所以这里我认为是最好的综合解决方案。

首先,把这些放在资源字典里。我将把编写VisibilityBoolean转换器作为一项练习留给读者,以确保复选框在列可见时选中,反之亦然。注意,通过为上下文菜单资源定义x:Shared="False",它将获得特定于实例的状态,这意味着你可以为所有的数据网格使用这个单一的templateresource,而且它们都会保持自己的状态。

<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-model暴露的一些数据源)。

<sdk:DataGrid ItemsSource="{Binding OrdersQuery}"
              AutoGenerateColumns="True" 
              ColumnHeaderStyle="{StaticResource ColumnHeaderStyle}"
              ContextMenu="{StaticResource GridItemsContextMenu}">

  <!-- rest of datagrid stuff goes here -->

</sdk:DataGrid>

这将给你带来以下内容。

  1. 一个上下文菜单 绑定到列标题上 作为一个列选择器。
  2. 一个绑定到网格中的项目的上下文菜单(对项目本身进行操作--再次强调,操作的绑定是读者的工作)。

希望这能帮助一直在寻找类似例子的人。


6
投票

我知道这有点老了。但我在看做这个,这个帖子就简单多了。http:/iimaginec.wordpress.com20110725binding-wpf-toolkit%E2%80%99s-datagridcolumn-to-a-viewmodel-datacontext-propogation-for-datagrid-columns-the-mvm-way-to-interact-with-datagridcolumn。

你所需要做的就是在Columns上设置DataContext,然后像平常一样将Visibility绑定到你的ViewModel上! :) 简单而有效


1
投票

好吧,对于一个WPF新手来说,这已经是相当大的练习了。

IanR谢谢你的建议,我用了一个类似的方法,但它不带你所有的方式。

下面是我想出的办法,如果有人能找到更一致的方法,我将感谢任何评论。

障碍:

  1. DataGridColumnHeader不支持上下文菜单。因此,上下文菜单需要作为一个样式应用。

  2. 上下文菜单有自己的数据上下文,所以我们必须使用findancestor将其链接到ViewModels的数据上下文。

  3. ATM DataGrid控件并没有将其数据上下文解析为Columns。这可以在codebehind中解决,但是我们使用的是MVVM模式,所以我决定按照下面的方法来解决。茉莉花 办法

解决方法:在Window.Resources中放入以下两块代码。

在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上的visibility属性和ischeked属性都是databound到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();

干杯。


0
投票

你可以用x:static代替booleanToVisibilityConverter。

<Setter TargetName="UIElement"  Property="UIElement.Visibility" Value="x:Static Visibility.Hidden" />

XAML中的静态。http:/msdn.microsoft.comen-uslibraryms742135.aspx。


-1
投票

我确实尝试过使用'元素名称'将其绑定到上下文菜单上,但最终,使用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>
© www.soinside.com 2019 - 2024. All rights reserved.