我的WPF应用程序中有一些XAML如下:
<ListView ItemsSource="{Binding}">
<ListView.View>
<GridView>
<GridViewColumn Width="{Binding RelativeSource={RelativeSource Self}, Converter={StaticResource myconverter}}">...
在myconverter
内,Convert()
方法,代码:
private static readonly PropertyInfo InheritanceContextProp = typeof(DependencyObject).GetProperty("InheritanceContext", BindingFlags.NonPublic | BindingFlags.Instance);
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
//the following does not work (parent returns null)
var gvc1 = (value as GridViewColumn);
var parent = InheritanceContextProp.GetValue(gvc1, null) as DependencyObject;
//the following works (parent is not null)
var gv = new GridView();
var gvc2 = new GridViewColumn();
gv.Columns.Add(gvc2);
parent = InheritanceContextProp.GetValue(gvc2, null) as DependencyObject;
return 0;
}
我尝试在LogicalTreeHelper.GetParent()
上使用VisualTreeHelper.GetParent()
和gvc1
,但这些都不起作用(返回null或抛出异常)。
任何人都可以解释发生了什么,为什么第二个例子有效?
答案 0 :(得分:0)
一个非常老的问题,但是我偶然遇到了这个问题,并且我有一个理论可以解释问题。
考虑在解析XAML时XAML处理器如何构建控件。向下浏览文件,它将创建一个ListView
,创建一个GridView
,然后将ListView.View
属性设置为该新的GridView
对象。意识到,它必须完成创建GridView
才能分配该属性。
现在进入<GridViewColumn ...
行。它必须先完成创建GridViewColumn
,然后才能将其添加到GridView.Columns
属性中。在解析行(创建GridViewColumn
)时,它遇到Width="{Binding ...
,并且必须评估绑定,这意味着还必须评估转换器。
因此,转换器在解析/创建GridViewColumn
之前被调用, 实际上是添加到GridView
中的,这解释了为什么它是“无父的”。
这说明了为什么第二个代码块起作用,即使第一个代码块不起作用。您要等到Columns.Add
之后再致电InheritanceContextProp.GetValue
。
您可以通过将以下代码添加到转换器中来进一步测试:
Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background, new Action(() =>
{
var gvc1 = (value as GridViewColumn);
var parent = InheritanceContextProp.GetValue(gvc1, null) as DependencyObject;
}));
这将在WPF完成加载所有内容之后运行代码 。如果您设置了断点,那么您已经等待了,您会看到parent
的设置确实正确。当然,这对于实际使用转换器没有帮助,但确实说明了为什么不起作用。