在WPF DependencyProperty

时间:2015-06-27 13:41:25

标签: wpf dependency-properties data-binding binding-expressions

我有一个以编程方式创建的绑定到一些标准WPF控件的DependencyProperty。当这个绑定与属性分离时,我希望调用我的函数。

可以将值更改通知附加到属性,但这意味着我需要重新检查每当实际值更新时绑定是否仍然存在,并且如果它做了很多它可能会影响绩效。

相关:Notification when the Source of a BindingExpression changes?

以下是我要完成的内容的详细信息

我正在编写一个类似WPF Canvas的控件,它具有自定义规则来放置,调整和旋转它的子项。

<my:MyCustomCanvas> 
    <Button my:Name="child control #1" Canvas.Left="10" Canvas.Top="20"/> 
    <my:SomeOtherControl my:Name="child control #2" Canvas.Left="70" Canvas.Top="80"/> 
</my:MyCustomCanvas>

要旋转子控件,我需要像这样设置RenderTransformProperty:

protected override void OnVisualChildrenChanged(DependencyObject visualAdded, DependencyObject visualRemoved)
{
    base.OnVisualChildrenChanged(visualAdded, visualRemoved);
    foreach (UIElement child in InternalChildren)
    {
        var group = new TransformGroup();
        var rt = new RotateTransform();
        var b = new Binding() { Source = ..., Convertor = ... };
        BindingOperations.SetBinding(rt, RotateTransform.AngleProperty, b);
        group.Children.Add(rt);
        child.RenderTransform = group;
    }
}

如果有人在设计器中调整子控件的大小,并且意外地使其宽度或高度为负,即使是一瞬间,设计者也会完全删除我的RenderTransform以将其替换为ScaleTransform {ScaleX = -1}。如果任何人或任何因任何原因设置或重置子控件的RenderTransform,也会发生同样的情况。恢复的唯一方法是关闭并重新打开设计器选项卡,这很烦人。

我唯一能做的就是订阅一个更改了值的事件,并在它们消失后重新应用绑定:

 var dpd = DependencyPropertyDescriptor.FromProperty(RenderTransformProperty, typeof(CustomCanvas));
 dpd.AddValueChanged(child, MyValueChangedHandler);

 static void MyValueChangedHandler(object sender, EventArgs e) 
 { 
      if ( ! /*do checks to see if my bindings are still untouched*/ ) 
            BindEverythingAgain();
 }

这是有效的,但可能在性能方面不是一个好主意,考虑到屏幕上有多达1000个控件,每个每秒更新大约60次 - 我必须为所有人请求绑定路径他们要正确检查他们是否被覆盖。

当属性未绑定时是否有要监听的事件

通过参考源查看我发现当更改依赖项属性数据源时,Expression.OnDetach()为called。但是,由于BindingExpression和MultiBindingExpression都是密封的,我需要继承BindingExpressionBase,这太过分了。

我还发现分离绑定时设置了BindingExpression.Status属性。因此,应该可以维护一个BindingExpressions列表并定期检查,这应该是性能更好的。虽然检查需要在计时器上运行,并且无法在值更改事件中执行,因此不是真正的干净解决方案,因为这需要在已知的列表中查找bindingexpression,这实际上不是快速操作,即使这样的列表已经排序。

0 个答案:

没有答案