WPF在DataGrid的Column中绑定Visibility属性,显示绑定异常Cannot find governing FrameworkElement or FrameworkContentElement
参考原文: https://thomaslevesque.com/2011/03/21/wpf-how-to-bind-to-data-when-the-datacontext-is-not-inherited/
翻译原文:https://blog.csdn.net/wdyxyyp/article/details/114486570
WPF中的DataContext属性非常方便,但在某些情况下,DataContext是不可访问的,比如,当你想绑定的元素不属于其逻辑树或可视树时,想正常使用绑定就可能非常困难……
让我们给一个简单的例子予以说明:我们要在DataGrid中显示产品列表。 在其中,我们希望能够基于ViewModel中公开的ShowPrice属性的值来显示或隐藏Price列。 一种明显的方法是将列的Visibility绑定到ShowPrice属性:
<DataGridTemplateColumn Header="| 类型" Width="104" Visibility="{Binding EnableSelectTagSense, Converter={StaticResource Boolean2VisibilityConverter }, Source={StaticResource proxy}}" >
但是,我们很快就会发现这样并不起作用,EnableSelectTagSense列会一直可见。为什么?如果我们看一下Visual Studio的Output窗口,会发现以下几行提示:
System.Windows.Data Error: 2 : Cannot find governing FrameworkElement or FrameworkContentElement for target element. BindingExpression:Path=EnableSelectTagSense; DataItem=null; target element is ‘DataGridTemplateColumn’ (HashCode=32685253); target property is ‘Visibility’ (type ‘Visibility’)
提示信息比较晦涩,但其实意思很简单:WPF不知道使用哪个FrameworkElement来获取DataContext,因为该列不属于DataGrid的逻辑树或可视树。
本问题使用下面两种方法都 没生效
方法一:
<DataGridTextColumn Header="Price" Binding="{Binding Price}" IsReadOnly="False"
Visibility="{Binding DataContext.ShowPrice,
Converter={StaticResource visibilityConverter},
RelativeSource={RelativeSource FindAncestor, AncestorType=DataGrid}}"/>
方法二:
<DataGridTextColumn Header="Price" Binding="{Binding Price}" IsReadOnly="False"
Visibility="{Binding IsChecked,
Converter={StaticResource visibilityConverter},
ElementName=chkShowPrice}"/>
当然还有一种不使用MVVM模式的方式更新,直接在XAML.cs文件中进行联动进行调整。不过这种方式 个人不推荐,但可以解决问题。
经过查资料,发现使用MVVM模式需要支持动态支持已经生成列的内容的Visibility等属性,需要XAML继承自 Freezable 类,然后在该页面的XAML中绑定该命名空间。
Freezable原本目的是定义具有可修改状态和只读状态的object,但有趣的是,Freezable可以继承那些甚至不在逻辑树或可视树中的DataContext。我目前还不清楚其背后的运行机理,但是我们可以利用这个优势完成我们的绑定工作。
方法是创建一个我称之为BindingProxy的继承了Freezable的类,以及定义了一个名为Data的依赖项属性:该段代码可以直接COPY
public class BindingProxy : Freezable
{
#region Overrides of Freezable
protected override Freezable CreateInstanceCore()
{
return new BindingProxy();
}
#endregion
public object Data
{
get { return (object)GetValue(DataProperty); }
set { SetValue(DataProperty, value); }
}
// Using a DependencyProperty as the backing store for Data. This enables animation, styling, binding, etc...
public static readonly DependencyProperty DataProperty =
DependencyProperty.Register("Data", typeof(object), typeof(BindingProxy));
}
然后,我们可以在DataGrid的资源中声明此类的实例,并将Data属性绑定到当前的DataContext:
<DataGrid.Resources>
<local1:BindingProxy x:Key="proxy" Data="{Binding}" />
</DataGrid.Resources>
最后一步是指定此BindingProxy对象作为绑定的源:
<DataGridTextColumn Header="Price" Binding="{Binding Price}" IsReadOnly="False"
Visibility="{Binding Data.ShowPrice,
Converter={StaticResource visibilityConverter},
Source={StaticResource proxy}}"/>
需要注意,绑定路径的前缀应为“ Data”,因为该路径现在是相对于BindingProxy对象的。完成之后,绑定就可以生效,根据ShowPrice属性正确显示或隐藏该列

浙公网安备 33010602011771号