WPF DataGrid:将DataGridColumn绑定到ContextMenu MenuItems IsChecked(MVVM)

时间:2009-10-13 15:12:11

标签: wpf xaml mvvm datagrid binding

我想通过右键单击列标题,通过用户可用的DataGrid控制ContextMenu列可见性。 ContextMenu显示所有可用列的名称。我正在使用MVVM设计模式。

我的问题是:如何将DataGridColumn的{​​{1}}属性绑定到位于Visibility的{​​{1}}的{​​{1}}属性。< / p>

一些模型代码:

IsChecked

... flaf flaf flaf

MenuItem

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

干杯,

6 个答案:

答案 0 :(得分:18)

我刚刚写了一篇关于这个主题的博文。它允许通过右键单击任何列标题可访问的ContextMenu显示或隐藏DataGridColumns。此任务完全通过附加属性完成,因此它符合MVVM。

See blog post

答案 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>

这将为您提供以下内容:

  1. 上下文菜单绑定到列标题,作为列选择器。
  2. 绑定到网格中项目的上下文菜单(对项目本身执行操作 - 再次,绑定操作是读者的练习)。
  3. 希望这可以帮助那些一直在寻找这样一个例子的人。

答案 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感谢您提出的建议,我使用了类似的方法,但它总是带你去。

如果有人能找到更一致的方法,我会想出以下内容我会感激任何评论:

阻碍:

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

  2. contextmenu有自己的datacontext,所以我们必须使用findancestor将它链接到ViewModels datacontext。

  3. ATM DataGrid控件不会将其datacontext解析为其Columns。这可以在代码隐藏中解决,但是我们使用MVVM模式,所以我决定遵循jamiers方法

  4. 解决方案:

    将以下两个代码块放在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>