WPF中DataGridTextColumn的Visibility绑定转换器未触发问题排查
首先看你遇到的错误提示:
System.Windows.Data Error: 2 : Cannot find governing FrameworkElement or FrameworkContentElement for target element. BindingExpression:Path=DataContext.Filter; DataItem=null; target element is 'DataGridTextColumn' (HashCode=20546761); target property is 'Visibility' (type 'Visibility')
这个错误的核心原因是:DataGridTextColumn不属于WPF可视化树的一部分,它没有自己的FrameworkElement实例,因此无法直接继承DataContext。你直接写Path=DataContext.Filter的时候,绑定找不到有效的数据源,自然不会触发转换器。
另外我还发现一个明显的笔误问题:你定义的枚举是EnumEstatRemesa,但ViewModel和转换器里用的是EnumStatus,类型完全不匹配,就算绑定成功,转换的时候也会抛出类型转换异常,这个得先修正!
接下来给你几个可行的解决方案:
方案1:通过RelativeSource绑定到DataGrid的DataContext
修改DataGridTextColumn的Visibility绑定,通过RelativeSource找到父级DataGrid,复用它的DataContext:
<my:DataGridTextColumn Visibility="{Binding Path=DataContext.Filter, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}, Converter={StaticResource ColumnVisibilityConverter}}">
方案2:使用ElementName绑定
给你的DataGrid设置一个x:Name,比如:
<DataGrid x:Name="MyMainDataGrid" ...>
然后列的绑定改成:
<my:DataGridTextColumn Visibility="{Binding Path=DataContext.Filter, ElementName=MyMainDataGrid, Converter={StaticResource ColumnVisibilityConverter}}">
方案3:用Freezable代理传递DataContext
如果上面两种方式不适用(比如DataGrid嵌套复杂),可以创建一个Freezable的代理类,它能在非可视化树元素中继承DataContext:
首先创建代理类:
public class BindingProxy : Freezable { protected override Freezable CreateInstanceCore() { return new BindingProxy(); } public object Data { get { return (object)GetValue(DataProperty); } set { SetValue(DataProperty, value); } } public static readonly DependencyProperty DataProperty = DependencyProperty.Register("Data", typeof(object), typeof(BindingProxy), new UIPropertyMetadata(null)); }
然后在Window的Resources中注册这个代理:
<Window.Resources> <ColumnVisibilityConverter x:Key="ColumnVisibilityConverter"/> <local:BindingProxy x:Key="DataContextProxy" Data="{Binding}" /> </Window.Resources>
最后修改列的绑定:
<my:DataGridTextColumn Visibility="{Binding Path=Data.Filter, Source={StaticResource DataContextProxy}, Converter={StaticResource ColumnVisibilityConverter}}">
最后必须修正的枚举类型问题
你当前的代码里枚举定义是EnumEstatRemesa,但ViewModel的属性是EnumStatus,转换器里也用EnumStatus,这三个类型必须统一!要么把枚举改名为EnumStatus,要么把ViewModel和转换器里的类型改成EnumEstatRemesa,否则类型转换会失败,转换器就算被调用也会出错。
按照上面的步骤修改后,你的转换器应该就能正常被调用了。
内容的提问来源于stack exchange,提问作者Willy

