We have two externally-defined, logically exclusive (business-wise) attached properties, both of which are inheritable. Depending on which was set closest to the DependencyObject we're reading them on, that determines which we use in our logic as seen below.
Note: I don't want to know that it is inherited which you can do via DependencyPropertyHelper.GetValueSource
, I want to know from where, so I can determine precedence.
Consider the following visual tree hierarchy and the attached properties:
Root // <-- AProp1 first set here
Child
GrandChild // <-- AProp2 first set here
GreatGrandChild // <-- AProp1 re-applied here
GreatGreatGrandChild
In the case of Root, AProp1 is set alone therefore we use AProp1.
In the case of Child, AProp1 is inherited therefore we still use AProp1.
In the case of GrandChild, AProp2 is set, but AProp1 also has a value thanks to inheritance. However, since AProp2 is set on this object directly (i.e. distance of '0' levels away) vs AProp1 (distance of '2' away), AProp2 takes precedence to our business logic.
In the case of GreatGrandChild, again since AProp1 is set (Distance of '0' away), that takes precedence over AProp2 (distance of '1' away)
Finally, in the case of GreatGreatGrandChild, again, both AProp1 and AProp2 are picked up via inheritance, however since AProp1 was set closer in the hierarchy (distance of '1' away) vs AProp2 (distance of '2' away), AProp1 is the one we want to use.
If I can find the source, I know I can simply walk the chain and count the distance away. I just need the source.
For the record, yes, they can both be set at the same level, in which case AProp2 would take precedence, but that's irrelevant to this question.
A property can also be re-applied (see GreatGrandChild) even using the same value as a way to bump its priority. That's why I need to know where the source is/how far it is from the element I'm checking.
I think I've found it. One of those 'Right in front of you all along' things. It revolves around using DependencyPropertyHelper.GetValueSource
to determine if a property value for an object is inherited or not.
That by itself of course doesn't tell you enough, but it's easy to go from there.
With that knowledge, you simply write a method which takes in the object in question and checks for the existence of both properties (remember, they may be 'set' because of a default value, style, template or whatever) and proceed accordingly:
If only one of the two is set, that's the one you use and you're done. Process as needed.
If they are both set, use the same precedence that a single property uses. (i.e. Local
beats Inherit
, Inherit
beats Default
, etc.) You're just comparing the values of two properties sources against each other at the same level.
If their source is the same and it is not Inherit
, you use the one that takes precedence in your business logic (AProp2 in our case.)
If they are the same and it is Inherit
, you walk up the logical tree (or visual depending on your need) and recursively call the same function passing in the parent.
Of course if this property is subject to animations and other such things, then the logic becomes a little more complex, but in our case, it's either going to be set locally or inherited. Not really much else.
Pretty simple now that I'm looking at it. Hope this helps others!