1

I have a programmatically-created binding to a DependencyProperty of some standard WPF control. I would like my function to be called when this binding is detached from the property.

It is possible to attach a value change notification to the property, but that means I need to recheck if the binding is still in place whenever the actual value updates, and if it does that a lot it may impact performance.

Related: Notification when the Source of a BindingExpression changes?

.

Below are details on what I am trying to accomplish:

I'm writing a WPF Canvas-like control that has custom rules to place, size and rotate it's children.

<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>

To rotate child controls I need to set their RenderTransformProperty like this:

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;
    }
}

If anyone resizes a child control in the designer, and accidentally makes its width or height negative, even for a split-second, designer deletes my RenderTransform completely to replace it with ScaleTransform{ ScaleX = -1 }. Same happens if anyone or anything sets or resets child control's RenderTransform for any reason. The only way to recover is to close and reopen designer tab, which is annoying.

The only thing I managed to do is to subscribe to a value changed event and reapply bindings if they are gone:

 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();
 }

This works, but is probably not a great idea performance-wise, considering I have up to 1000 controls onscreen, each updating around 60 times per second - and I have to request binding paths for all of them to properly check if they were not overwritten.

Isn't there an event to listen when a property is unbound?

Looking through reference source I have found that when a dependency property data source is changed, Expression.OnDetach() is called. However, since both BindingExpression and MultiBindingExpression are sealed, I would need to subclass BindingExpressionBase which is way too much work.

I also found BindingExpression.Status property is set when a binding is detached. Therefore, it should be possible to maintain a list of BindingExpressions and check that regularly, which should probably be much better performance-wise. Is is not really a clean solution though as checking needs to run on a timer, and cannot be done in a value changed event since that would require to look up a bindingexpression in the list of known ones, which is not really a fast operation, even if such list is sorted.

Community
  • 1
  • 1
Shambler0
  • 31
  • 4
  • Found related question: http://stackoverflow.com/questions/22909373 - Notify when the binding of Dependency Property is changed. No better answer there either currently, however... To moderators: this question is **not** fully duplicate of that one: mine is specifically about a WPF control (i.e. descendant from FrameworkElement class) and enenkey's is specifically about bare DependencyObject, that is why he said my partial solution (Value Changed events) would not work for him – Shambler0 Jun 27 '15 at 17:38
  • Okay, after some more searching and reading, I found a forum post by someone from MSDN support saying there is no such notification: https://social.msdn.microsoft.com/Forums/vstudio/en-US/4a608d36-f005-4007-8d37-5ebaae3120c3?forum=wpf ||| I don't know if I should delete the question though - or leave for others to find that it, sadly, cannot be done... – Shambler0 Jun 27 '15 at 18:07
  • 1
    If you're confident in the answer you've come up with (even if that answer is 'it can't be done'), it's perfectly valid to post it as an answer to your own question. That allows for future discussion, and marks the question 'answered'. – goobering Jun 28 '15 at 11:10

0 Answers0