绑定 datagrid 列可见性 MVVM

Posted

技术标签:

【中文标题】绑定 datagrid 列可见性 MVVM【英文标题】:Bind datagrid column visibility MVVM 【发布时间】:2011-12-04 09:45:10 【问题描述】:

.Net 3.5

我知道这些列不继承数据上下文,通过阅读其他帖子,我认为这会起作用:

Visibility="Binding RelativeSource=x:Static RelativeSource.Self,
                     Path=(FrameworkElement.DataContext).IsColumnNameVisible,
                     Converter=StaticResource boolToVisConverter"

当然不是.. 输出窗口没有报错,似乎是我找到的资源,但是viewmodel属性是新调用的。

这是整个 DG:

<tk:DataGrid                                        
            VirtualizingStackPanel.IsVirtualizing="False"                                        
            Grid.Column="0"
            AlternationCount="2"
            AreRowDetailsFrozen="True"
            AutoGenerateColumns="False"
            Background="Transparent"
            BorderThickness="0"
            CanUserAddRows="False"
            CanUserReorderColumns="True"
            CanUserResizeRows="False"
            GridLinesVisibility="None"
            ItemsSource="Binding Employees"
            SelectionMode="Single"
            ColumnHeaderStyle="StaticResource columnHeaderStyle"
            RowHeaderStyle="StaticResource rowHeaderStyle"
            CellStyle="StaticResource cellStyle"
            RowStyle="StaticResource rowStyle" 
            ContextMenu="StaticResource columnHeaderContextMenu">
    <tk:DataGrid.Resources>
        <ContextMenu x:Key="columnHeaderContextMenu" ItemsSource="Binding ColumnHeaderContextMenuItems" />
        <Style TargetType="x:Type ScrollBar">
            <Setter Property="Background" Value="Transparent"/>
        </Style>                                    
        <Style TargetType="x:Type tk:DataGridColumnHeader">
            <Setter Property="Background" Value="Transparent"/>
        </Style>
    </tk:DataGrid.Resources>
    <tk:DataGrid.Triggers>
        <EventTrigger RoutedEvent="tk:DataGridRow.MouseDoubleClick">
            <EventTrigger.Actions>
                <BeginStoryboard Storyboard="StaticResource showDetailGrid"/>
            </EventTrigger.Actions>
        </EventTrigger>
    </tk:DataGrid.Triggers>
    <tk:DataGrid.Columns>
        <tk:DataGridTextColumn IsReadOnly="True" Header="test" Binding="Binding Name, Mode=OneWay" Visibility="Binding RelativeSource=x:Static RelativeSource.Self, Path=(FrameworkElement.DataContext).IsColumnNameVisible, Converter=StaticResource boolToVisConverter"  />
    </tk:DataGrid.Columns>
</tk:DataGrid>

我已经阅读了该问题的几乎所有解决方案,但没有任何效果..

【问题讨论】:

如果您的问题有点不清楚。您是否只是试图根据绑定的 ViewModel 属性使数据列可见或不可见? 您在 &lt;tk:DataGrid.Resources&gt; 中更改了 ContextMenu - 难怪您的窗口 DataContext 无法访问。 @ChrisBD:是的,就是这个想法。 VM 属性是通过 datacontext 设置的。 @Felix:什么意思?它是一个上下文菜单。为什么这会影响数据上下文的可用性? 【参考方案1】:

DataGridColumns 不是可视化树的一部分,因此它们没有连接到 DataGrid 的数据上下文。

让他们连接一起使用像这样的代理元素方法...

    在祖先面板的Resources 中添加代理FrameworkElement。 将其托管到绑定到其Content 的不可见ContentControl 中。

    将此ProxyElement 用作StaticResource 作为可见性绑定中的数据上下文源。

    <StackPanel>
        <StackPanel.Resources>
           <local:BooleanToVisibilityConverter
                  x:Key="BooleanToVisibilityConverter" />
    
           <FrameworkElement x:Key="ProxyElement"
                             DataContext="Binding"/>
        </StackPanel.Resources>
        <ContentControl Visibility="Collapsed"
                    Content="StaticResource ProxyElement"/>
        <DataGrid AutoGenerateColumns="False">
            <DataGrid.Columns>
                <DataGridTextColumn
                       Visibility="Binding DataContext.IsTextColumnVisibile,
                                            Source=StaticResource ProxyElement,
                                            Converter=StaticResource
                                                BooleanToVisibilityConverter"
                       Binding="Binding Text"/>
            </DataGrid.Columns>
        </DataGrid>
    </StackPanel> 
    

除了DataGridColumn,上述方法还可以很好地将DataContext 连接到Popups 和ContextMenus(即任何未连接到可视化树的元素)。

Silverlight 用户

遗憾的是,silverlight 中不允许使用任何框架元素设置内容控件的内容。所以解决方法是(这只是silverlight的指导代码)......

    将框架元素资源更改为像Textblock 这样的轻量级元素。 (Silverlight 不允许指定 FrameworkElement 类型的静态资源。)

    <StackPanel.Resources>
        <TextBlock x:Key="MyTextBlock" />
    

    编写一个附加属性以将文本块与内容控件保持一致。

    <ContentControl Visibility="Collapsed" 
                    local:MyAttachedBehavior.ProxyElement="StaticResource MyTextBlock" />
    

    在附加的依赖属性更改事件处理程序中,设置将内容控件的数据上下文绑定到文本块的。

     private static void OnProxyElementPropertyChanged(
         DependencyObject depObj, DependencyPropertyChangedEventArgs e)
     
           if (depObj is ContentControl && e.NewValue is TextBlock)
           
               var binding = new Binding("DataContext");
               binding.Source = depObj;
               binding.Mode = OneWay;
               BindingOperations.SetBinding(
                   (TextBlock)e.NewValue, TextBlock.DataContextProperty, binding);
           
     
    

因此,这样文本块可能不会连接到可视化树,但会可能知道数据上下文的变化。

希望这会有所帮助。

【讨论】:

取消选择和重新选择时出现异常:指定元素已经是另一个元素的逻辑子元素。先断开它。你知道为什么吗? 可能是你的ContextMenu ...它只能附加到一个父母。 将 ContextMenu 更改为 DataGrid CM 而不是 DGColumnHeader CM,但它没有帮助。如果这很重要,我会在多个列上使用它.. @WPF-如果我们仍然使用ProxyElement,你能解释一下为什么这里需要ContentControl吗? This 解决方案使用类似的方法,但不需要ContentControl @monstr,Freezable 类破解了DataContext ...在我们的例子中,'proxyelement' 不是 Freezable,所以如果它托管在@987654346 中,它可以获得DataContext 的唯一方法@ 如果它是 ContentContentControl,则这是可能的。同样对于链接中的第二个解决方案,NameScoping 没有像DataGridColumnHeaderTemplate 一样在Template 中解析,所以ElementName 不起作用。我提供的解决方案可以解决这两种情况。

以上是关于绑定 datagrid 列可见性 MVVM的主要内容,如果未能解决你的问题,请参考以下文章

WPF DataGrid的可见性

如何在自定义 wpf 控件上绑定数据网格列的可见性?

如何将 WPF DataGrid DataColumns 可见性绑定到 UserControl 的 ViewModel 上的属性?

使用转换器的DataGridColumn可见性

绑定到可见性属性时动画不正确(奇数)

DataGridTextColumn 可见性绑定