我试图获得控件相对于窗口顶部的偏移量,但是在使用控件的TransformToAncestor方法时遇到了麻烦.注意:此代码位于值转换器中,该转换器将从控件转换为相对于窗口的相对Y位置.
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;
}
Run Code Online (Sandbox Code Playgroud)
调用Window.GetWindow工作正常,并返回控件所在的正确窗口对象.
我误解了WPF认为的"祖先"吗?我认为,鉴于结果GetWindow,该窗口将成为控制的祖先.是否有某些嵌套图案会导致某一系列的血统被切断?
更新:
看起来这可能是一个时间问题.当我尝试TransformToAncestor在事件处理程序而不是值转换器中调用方法时,它工作得很好.似乎值转换器必须运行,因为在建立祖先关系之前实例化某些元素.
不知道如何解决这个问题,因为我正在尝试使用MVVM模式(因此我并不真的想使用事件处理程序,而是宁愿在我的ViewModel中没有System.Windows的东西).
在可视树仍在组装时调用转换器,因此您的Visual还不是Window的后代.
您希望在构建可视树后进行转换.这是通过在回调中使用Dispatcher.BeginInvoke(DispatcherPriority.Render, ...)和执行您的工作来注册Dispatcher回调来完成的.
但是,这不能与转换器一起使用,因为转换器必须立即返回转换后的值.简单的解决方法是使用附加属性而不是转换器.这是如何做:
假设你的绑定是这样的:
<SomeObject Abc="{Binding Xyz, Converter={x:Static my:Converter.Instance}}" />
Run Code Online (Sandbox Code Playgroud)
创建一个DependencyObject子类"Whatever",其中包含附加属性"AbcControl",其PropertyChangedCallback执行转换并修改"Abc"属性:
public class AttachedProperties : DependencyObject
{
public Control GetAbcControl(...
public void SetAbcControl(...
... AbcControlProperty = RegisterAttached("AbcControl", typeof(Control), typeof(AttachedProperties), new PropertyMetadata
{
PropertyChangedCallback = (obj, e) =>
{
var ctrl = (Control)e.NewValue;
Dispatcher.BeginInvoke(DispatcherPriority.Render, new Action(() =>
{
var win = Window.GetWindow(ctrl);
var transform = ctrl.TransformToAncestor(win); // Exception thrown here.
var pt = transform.Transform(new Point(0, 0));
obj.SetValue(AbcProperty, pt.Y);
});
}
});
}
Run Code Online (Sandbox Code Playgroud)
现在你可以写:
<SomeObject AbcControl="{Binding Xyz}" />
Run Code Online (Sandbox Code Playgroud)
这将Abc属性设置为已转换的Y值.
这个总体思路可能有很多变化.
| 归档时间: |
|
| 查看次数: |
4710 次 |
| 最近记录: |