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

C# 如何将Datagrid列的可见性绑定到WPF中的复选框,c#,wpf,xaml,C#,Wpf,Xaml,我在DataGrid中有几个列,我希望根据该列的复选框显示或隐藏这些列。我事先搜索了不少,找到了许多不同的答案,但在每种情况下,它们要么不起作用,要么针对不同的情况 如果我理解正确,ElementName将无法工作,因为可视化树不可用。然而,我尝试设置源和相对源,但没有任何运气。在当前状态下,它返回错误:未解析的引用“filterDuration”。该错误使程序停止运行 更新了以下建议和更多信息,但仍未解决 这是转换器:(它甚至从来没有进入这一步) 以下是复选框: <DataTemplat

我在DataGrid中有几个列,我希望根据该列的复选框显示或隐藏这些列。我事先搜索了不少,找到了许多不同的答案,但在每种情况下,它们要么不起作用,要么针对不同的情况

如果我理解正确,ElementName将无法工作,因为可视化树不可用。然而,我尝试设置源和相对源,但没有任何运气。在当前状态下,它返回错误:未解析的引用“filterDuration”。该错误使程序停止运行

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

这是转换器:(它甚至从来没有进入这一步)

以下是复选框:

<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:(为了简洁起见,删除了额外的列和属性)


您的示例对我很有用,您不应该被设计器中的错误弄糊涂,在运行时它是有效的-x:引用绑定似乎让设计器有点困惑

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

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


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

您的示例对我来说很有用,您不应该被设计器中的错误弄糊涂,在运行时它是有效的-x:引用绑定似乎会让设计器非常困惑

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

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


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

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

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

  • 在参考资料部分下声明一个虚拟复选框
  • 使用此虚拟复选框绑定已检查filterDuration
  • 使用虚拟复选框IsChecked属性绑定DataGridTextColumn的可见性

  • 代码:

    
    .........
    ......... 
    
    在数据模板中:

    
    
    注意-如果无法从dataTemplate中的Dockpanel resources部分访问资源,您还可以在window resources部分下声明该资源


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

  • 在ViewModel中具有布尔属性
  • 将filterDuration复选框绑定到该绑定属性
  • 将dataGrid列的可见性绑定到绑定的bool属性

  • DataTemplate内的控件没有相同的名称范围,因此不能通过ElementName或x:Reference从其名称范围外的控件绑定

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

  • 在参考资料部分下声明一个虚拟复选框
  • 使用此虚拟复选框绑定已检查filterDuration
  • 使用虚拟复选框IsChecked属性绑定DataGridTextColumn的可见性

  • 代码:

    
    .........
    ......... 
    
    在数据模板中:

    
    
    注意-如果无法从dataTemplate中的Dockpanel resources部分访问资源,您还可以在window resources部分下声明该资源


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

  • 在ViewModel中具有布尔属性
  • 将filterDuration复选框绑定到该绑定属性
  • 将dataGrid列的可见性绑定到绑定的bool属性

  • 在小样本中进行了尝试,您的代码在我这边运行良好
    <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>
    
    <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>
    
    <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>
    
    <CheckBox x:Name="filterDuration" Content="Duration"
             IsChecked="{Binding IsChecked, Source={StaticResource DummyCheckBox}}"/>