WPF DataGrid - 使用复选框隐藏列
我正在尝试使用复选框控制列的可见性(这是在 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 向我指出了答案。他指出的页面有点误导,因为帖子中列出的代码不起作用,您必须查看示例代码。
这是我的最终工作代码,供遇到此问题的其他人使用:
Converter 将我们的 ViewModels bool 属性转换为列属性的正确可见性值。
<Window.Resources>
<BooleanToVisibilityConverter x:Key="BoolToVisConverter" />
</Window.Resources>
将复选框绑定到将控制列可见性的 ViewModels 属性。
<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>
将以下代码添加到您的项目中,这允许捕获 DataGrids DataContext 中的更改。
FrameworkElement.DataContextProperty.AddOwner(typeof(DataGridColumn));
FrameworkElement.DataContextProperty.OverrideMetadata(typeof(DataGrid),
new FrameworkPropertyMetadata
(null, FrameworkPropertyMetadataOptions.Inherits,
new PropertyChangedCallback(OnDataContextChanged)));
然后,每当您的 DataGrids DataContext 发生更改时,我们都会使用新的 DataContext 更新所有附加的 DataGridColumsn。
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);
}
}
}
有一个需要注意的问题。如果您将 DataContext 添加到您的页面,如下所示:
<Window.DataContext>
<vm:WeaponListViewModel />
</Window.DataContext>
那么上述函数将在您的 DataGrid 有任何列之前被调用!
我通过在创建窗口后在代码后面手动附加 DataConext 来解决这个问题。
I am trying to control the visibility of a column using a checkbox (this is in WPF 4.0).
Here is a snippet of my 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>
Now I know the BooleanToVisibilityConverter converter is working as I bound it to a text block and I can see the values I am expecting. If I enter the values by hand into the columns visibility property it works. But not when I bind it. What am I doing wrong?
Answer:
Quartermeister pointed me to the answer. The page he pointed to is a bit misleading as the code listed on the post does not work and you must look at the sample code.
Here is my final, working code, for anyone else who runs into this problem:
Converter to turn our ViewModels bool property into the correct Visibility value for our column attribute.
<Window.Resources>
<BooleanToVisibilityConverter x:Key="BoolToVisConverter" />
</Window.Resources>
Bind the checkbox to the ViewModels property that will control the columns visibiity.
<CheckBox
x:Name="DetailsVisible"
Content="Show Details"
IsChecked="{Binding Path=DisplayDetails}" />
Then bind Visibility to the ViewModels DisplayDetails property. Notice that it is the columns own DataContext that is bound to.
<DataGridTextColumn
Header="Reliability"
Binding="{Binding Path=Reliability}"
Visibility="{Binding (FrameworkElement.DataContext).DisplayDetails,
RelativeSource={x:Static RelativeSource.Self},
Converter={StaticResource BoolToVisConverter}}">
</DataGridTextColumn>
Add the following code to your project, this allows the catching of the change in a DataGrids DataContext.
FrameworkElement.DataContextProperty.AddOwner(typeof(DataGridColumn));
FrameworkElement.DataContextProperty.OverrideMetadata(typeof(DataGrid),
new FrameworkPropertyMetadata
(null, FrameworkPropertyMetadataOptions.Inherits,
new PropertyChangedCallback(OnDataContextChanged)));
Then whenever your DataGrids DataContext is changed we update all the attached DataGridColumsn with the new DataContext.
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);
}
}
}
One Gotcha to look out for. If you add your DataContext to your page like so:
<Window.DataContext>
<vm:WeaponListViewModel />
</Window.DataContext>
Then the above function will be called before your DataGrid has any columns!
I got around this by manually attaching my DataConext in code behind after the window was created.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
IMO 使用
x:Name
、x:Reference
和Source
更简单:请参阅此答案:
将可见性绑定到可检查菜单项显示错误“服务提供程序缺少 INameResolver 服务” “在 WPF 中
IMO using
x:Name
,x:Reference
andSource
is simpler:See this answer:
Bind visibility to checkable menu item shows error "Service provider is missing the INameResolver service" in WPF
问题在于 DataGrid 列不是可视化树的一部分,因此它们无法使用绑定。 (“Binding”属性实际上是 Binding 类型的普通属性,而不是依赖属性。它将该绑定对象应用于单元格,这些单元格是可视化树的一部分。)
这里是一个博客链接,其中包含解决方法和演示将列的可见性绑定到复选框: 链接
The problem is that the DataGrid columns are not part of the visual tree, so they cannot use bindings. (The "Binding" property is actually a normal property of type Binding, not a dependency property. It applies that binding object to the cells, which are part of the visual tree.)
Here is a link to a blog that has a workaround and demonstrates binding the visibility of a column to a check box: Link