WPF数据网格 - 使用复选框隐藏列

10

我正在尝试使用复选框控制列的可见性(这是在WPF 4.0中实现的)。

以下是我的XAML代码片段:

<Window.Resources>
    <BooleanToVisibilityConverter x:Key="BoolToVisConverter" />
</Window.Resources>

<CheckBox x:Name="GeneralDetailsVisible" Content="General Details"  Margin="5"/>

<DataGridTextColumn Header="Crew" 
  Binding="{Binding Path=Crew}" 
  Visibility="{Binding ElementName=GeneralDetailsVisible, 
                       Converter={StaticResource BoolToVisConverter}, 
                       Path=IsChecked}">
</DataGridTextColumn>

现在我知道BooleanToVisibilityConverter转换器正在工作,因为我将其绑定到文本块上,我可以看到我期望的值。如果我手动将值输入到列可见性属性中,则可以正常工作。但是当我绑定它时就不行了。我做错了什么?
答案:
Quartermeister指向了答案。他指向的页面有点误导人,因为帖子上列出的代码不起作用,你必须查看示例代码。
这是我的最终工作代码,供其他遇到此问题的人使用:
转换器将我们的ViewModels bool属性转换为适合列属性的正确可见性值。
<Window.Resources>
    <BooleanToVisibilityConverter x:Key="BoolToVisConverter" />
</Window.Resources>

将复选框绑定到控制列可见性的ViewModel属性。

<CheckBox
  x:Name="DetailsVisible" 
  Content="Show Details"
  IsChecked="{Binding Path=DisplayDetails}" />

然后将Visibility绑定到ViewModels的DisplayDetails属性。请注意,绑定的是列自己的DataContext。
<DataGridTextColumn
  Header="Reliability" 
  Binding="{Binding Path=Reliability}" 
  Visibility="{Binding (FrameworkElement.DataContext).DisplayDetails, 
                       RelativeSource={x:Static RelativeSource.Self}, 
                       Converter={StaticResource BoolToVisConverter}}">
</DataGridTextColumn>

将以下代码添加到您的项目中,这将允许捕获DataGrid的DataContext中的更改。
FrameworkElement.DataContextProperty.AddOwner(typeof(DataGridColumn));

FrameworkElement.DataContextProperty.OverrideMetadata(typeof(DataGrid),
        new FrameworkPropertyMetadata
           (null, FrameworkPropertyMetadataOptions.Inherits,
           new PropertyChangedCallback(OnDataContextChanged))); 

每当您的DataGrid的DataContext更改时,我们会使用新的DataContext更新所有附加的DataGridColumn。

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);
        }
    }
}

需要注意的一个陷阱是,如果你像这样将你的数据上下文添加到页面中:

<Window.DataContext>
    <vm:WeaponListViewModel />
</Window.DataContext>

那么在你的DataGrid有任何列之前,上述函数将被调用!

我通过在窗口创建后在代码后台手动附加我的DataConext来解决了这个问题。


在我看来,使用起来更容易。 - testpattern
2个回答

8

我认为使用x:Namex:ReferenceSource更加简单:

<Window.Resources>
    <BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
</Window.Resources>

<CheckBox x:Name="showImperial" Content="Show Details" />

<DataGrid>
<DataGrid.Columns>
<DataGridTextColumn Header="TOV (Bls)" 
                    Width="80" 
                    Binding="{Binding TOVBarrels}"
                    Visibility="{Binding Source={x:Reference showImperial},
                                 Path=IsChecked, 
                                 Converter={StaticResource BooleanToVisibilityConverter}}"/>
</DataGrid.Columns>
</DataGrid>

请看这个答案:将可选菜单项的可见性绑定显示"WPF中缺少INameResolver服务"错误


尝试了这个确切的事情,但它只是给我一个错误:“未解决的引用showImperial”。 - jrandomuser

3
问题在于DataGrid列不是可视树的一部分,因此它们不能使用绑定。("Binding"属性实际上是一个类型为Binding的普通属性,而不是依赖属性。它将该绑定对象应用于单元格,这些单元格是可视树的一部分。)
以下是一个博客链接,其中提供了一种解决方法并演示了如何将列的可见性绑定到复选框:链接

链接断了,经过12年,但问题仍然存在... - Philipp Michalski

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接