我有一个以编程方式创建的绑定到一些标准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,这实际上不是快速操作,即使这样的列表已经排序。