Search code examples
c#wpfbindingpropertypath

From code, how can you create a binding to a property on an object stored in an attached property?


We have an inheriting attached property which stores an object. Further down the visual tree, we want to bind to a property on that object from code.

Normally we construct the Path portion of a binding like so...

var someBinding = new Binding()
{
    Path = new PropertyPath(AttachedPropertyOwner.SomeAttachedProperty),
    RelativeSource = new RelativeSource(RelativeSourceMode.Self)
}; 

That works, but we now want a property of the object stored in SomeAttachedProperty. I take it we're supposed to use the string representation?

Also, while researching this, I found this on MSDN: Property Path Syntax

The concerning part is down under the heading 'PropertyPathInCode'

If you construct a PropertyPath from a DependencyProperty, that PropertyPath is not usable as a Binding.Path, it is only usable for animation targeting. The Path value for the constructed PropertyPath from a DependencyProperty is the string value (0), which is a sentinel value used by the binding engine for an invalid path.

...which doesn't make sense to me since it appears to work fine. Am I missing something? Have we been doing all of our code bindings wrong?

Update

Reading the MSDN documentation comment (which I missed was Silverlight, but I don't think matters in this case), it says you can't use a Dependency Property. However, it says you can use a DependencyProperty identifier, the identifier being what's returned from the Register methods.

In other words, I think what they're saying is what we're doing is valid...

var someBinding = new Binding()
{
    Path = new PropertyPath(CarClass.WheelCountProperty)
}; 

...but this is not.

var someBinding = new Binding()
{
    Path = new PropertyPath(MyCarInstance.WheelCount)
}; 

Seemingly confirming this, under the hood, Reflector shows it's essentially just doing this...

public PropertyPath(object value)
: this("(0)", new [] { value })
{
    ....
}

...so I think that scare was a red herring.

I think that also means I can do what I'm after like this...

Path = new PropertyPath("(0).(1)",
    SomeClass.SomeAttachedProperty,
    SomeOtherClass.SomeOtherAttachedProperty)

...which gets the value of the second attached property from the object stored in the first attached property.


Solution

  • I just confirmed my earlier suspicion was correct. Here's all you have to do to bind to an attached property on the value stored in another attached property...

    Path = new PropertyPath("(0).(1)",
        SomeClass.SomeAttachedProperty,
        SomeOtherClass.SomeOtherAttachedProperty)
    

    As stated in the update, for simple properties, this is also valid.

    Path = new PropertyPath(SomeClass.SomeAttachedProperty)
    

    ...which essentially is the equivalent of this...

    Path = new PropertyPath("(0)",
        SomeClass.SomeAttachedProperty)