如何将Datagrid列的可见性绑定到WPF中的复选框

时间:2014-08-22 18:29:23

标签: c# wpf xaml

我在DataGrid中有几个列,我想基于CheckBox为该列显示或隐藏它们。我事先搜索了很多,发现了许多不同的答案,但在每种情况下,他们要么没有工作,要么针对不同的情况。

如果我理解正确,ElementName不会起作用,因为Visual Tree不可用。但是我试过设置Source和RelativeSource而没有任何运气。在当前状态下,它简单地返回错误:未解析的参考' filterDuration'。该错误会使程序停止运行。

更新了以下建议和更多信息,但仍未解决

这是转换器:(它甚至从未涉及到这一点)

[ValueConversion(typeof(bool), typeof(Visibility))]
public class FilterVisibilityConverter : IValueConverter
{ 
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        bool isSelected = System.Convert.ToBoolean(value);

        return isSelected ? Visibility.Visible : Visibility.Hidden;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        var v = (Visibility)value; 
        return v == Visibility.Hidden ? false : true;
    }
}

这是CheckBox:

<DataTemplate x:Key="Settings">
        <DockPanel>                 
            <GroupBox Header="Filter Columns" DockPanel.Dock="Right">
                <ag:AutoGrid Columns="150, 150, 150" RowCount="7" RowHeight="20"> 
                    <CheckBox Content="Id" />
                    <CheckBox Content="Desc" />
                    <CheckBox x:Name="filterDuration"  Content="Duration" />                          
                </ag:AutoGrid>
            </GroupBox>
        </DockPanel>
    </DataTemplate>

以下是DataGrid :(为简洁起见,删除了额外的列和属性)

<DockPanel Grid.Row="0" Grid.Column="0">
        <Expander  DockPanel.Dock="Top" Header="{x:Static p:Resources.shSettings}"  ContentTemplate="{StaticResource Settings}" IsExpanded="True" />
        <Border DockPanel.Dock="Top" Background="#FF595959">
            <TextBlock Text="{x:Static p:Resources.shViolations}" Style="{StaticResource SectionHeaderText}" /> 
        </Border>
        <DataGrid IsReadOnly="True" ItemsSource="{Binding items}" SelectedItem="{Binding Path=selecteditem}" AutoGenerateColumns="False"    >
            <DataGrid.Columns>
                <DataGridTextColumn Header="Duration" Binding="{Binding Duration}" Visibility="{Binding Source={x:Reference filterDuration}, Path=IsChecked, Converter={StaticResource FilterVisibility}}" />
                <DataGridTextColumn Header="CTG Id" Binding="{Binding Id}" />
            </DataGrid.Columns>
        </DataGrid>
    </DockPanel>

2 个答案:

答案 0 :(得分:2)

你的例子对我有用,你不应该让自己对设计师的错误感到困惑,在运行时它可以工作 - x:参考绑定似乎让设计师有点混淆。

除此之外,您的值转换器中存在一些小错误:

  • ConvertBack返回'value'是错误的,它应该将Visbility转换为Boolean。 您应该正确实现这一点,因为您进行了双向绑定。 (虽然我不确定你为什么这样做,但我会说单向绑定就足够了。列的可见性毕竟不是用户可以改变的,所以不需要再传播它的更改到复选框,对吗?)
  • 您应该在类的属性中声明值转换器处理的类型: [ValueConversion(typeof(bool), typeof(Visibility))]

<强>更新

根据您更新的问题,您需要一种方法来链接不同的上下文。如果您无法通过向ViewModel添加属性来执行此操作,则仍可以创建资源对象。 Rohit Vats的另一个答案是将CheckBox滥用为这样的资源对象。如果您想要一种“更干净”的方式,只需为已检查状态定义一个带有DependencyProperty的新DependencyObject子类,然后将该类的实例放入静态资源中。然后可以使用此资源使控件相互通信。

答案 1 :(得分:1)

DataTemplate内部的控件没有相同的名称范围,因此无法通过ElementName或x:Reference来绑定名称范围之外的控件。

作为一种解决方法,您可以通过以下方式实现这一目标:

  1. 在资源部分下声明一个虚拟复选框。
  2. 使用此虚拟复选框绑定过滤器的IsChecked。
  3. 使用虚拟复选框IsChecked属性绑定DataGridTextColumn的可见性。

  4. 代码:

    <DockPanel .....>
       <DockPanel.Resources>
          <CheckBox x:Key="DummyCheckBox"/>
       </DockPanel.Resources>
       .........
          <DataGridTextColumn Header="Duration" Binding="{Binding Duration}"
              Visibility="{Binding Source={StaticResource DummyCheckBox}, 
                      Path=IsChecked, Converter={StaticResource FilterVisibility}}"/>
       ......... 
    </DockPanel>
    

    DataTemplate

    <CheckBox x:Name="filterDuration" Content="Duration"
             IsChecked="{Binding IsChecked, Source={StaticResource DummyCheckBox}}"/>
    

    注意 - 如果无法从dataTemplate中的Dockpanel资源部分访问该资源,您也可以在窗口资源部分声明该资源。


    显然,理想的解决方案是:

    1. 在ViewModel中拥有bool属性。
    2. 将filterDuration复选框绑定到该绑定属性。
    3. 将dataGrid列的可见性绑定到该绑定的bool属性。