Wpf 使用TransformToAncestor时出错:“0”;指定的视觉对象不是此视觉对象的祖先。”;
我试图获取控件相对于其窗口顶部的偏移量,但在使用控件的TransformToAncestor方法时遇到了问题。注意:此代码位于值转换器中,它将从控件转换为相对于窗口的相对Y位置Wpf 使用TransformToAncestor时出错:“0”;指定的视觉对象不是此视觉对象的祖先。”;,wpf,Wpf,我试图获取控件相对于其窗口顶部的偏移量,但在使用控件的TransformToAncestor方法时遇到了问题。注意:此代码位于值转换器中,它将从控件转换为相对于窗口的相对Y位置 public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { var ctrl = (Control) value; var win = Window.GetWindow(ctrl
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var ctrl = (Control) value;
var win = Window.GetWindow(ctrl);
var transform = ctrl.TransformToAncestor(win); // Exception thrown here.
var pt = transform.Transform(new Point(0, 0));
return pt.Y;
}
对Window.GetWindow
的调用工作正常,并返回控件所在的正确窗口对象
我是否误解了WPF对“祖先”的看法?我认为给定GetWindow
的结果,该窗口将是控件的祖先。是否有某些筑巢模式会导致祖先的血统在某一点被切断
更新:
看起来这可能是个时间问题。当我尝试在事件处理程序中调用TransformToAncestor
方法而不是值转换器时,它工作得很好。似乎在祖先关系建立之前,值转换器必须在实例化某些元素时运行
我不知道如何解决这个问题,因为我正在尝试使用MVVM模式(因此我不想使用事件处理程序,也不希望在我的ViewModel中使用System.Windows内容)。在可视化树仍在组装时调用转换器,因此您的可视化还不是该窗口的后代 您希望在构建可视化树后进行转换。这是通过使用Dispatcher.BeginInvoke(DispatcherPriority.Render,…)注册Dispatcher回调并在回调中执行您的工作来完成的 但是,这不能用于转换器,因为转换器必须立即返回转换后的值。简单的解决方法是使用附加属性而不是转换器。以下是方法: 假设您的绑定是这样的:
<SomeObject Abc="{Binding Xyz, Converter={x:Static my:Converter.Instance}}" />
现在你可以写:
<SomeObject AbcControl="{Binding Xyz}" />
将Abc属性设置为转换后的Y值
在这个总的想法上有许多可能的变化
<SomeObject AbcControl="{Binding Xyz}" />