Demystifying dependency properties

There is something very important to know about dependency properties.  Once you understand this fundamental point, much of WPF becomes more intuitive.

The value of a dependency property is resolved. 

Normal CLR properties (i.e. not dependency properties) typically provide a getter and/or setter with which the value of a private field can be retrieved and/or modified.  When you set a normal CLR property, you might usually think of it as assigning a value to a field.  Usually whatever value you set a property to is the value which is returned when you access its getter.  Of course, properties can contain other logic which executes before and after the field is modified or returned.  That’s a major reason why they exist.

Dependency properties are a different animal altogether.  They never represent a private field in your class.  You can assign a DP a specific value, but that is not necessarily the value which will be returned when you access its getter.  Even if your DP has no validation or value coercion logic, you still might not get back the same value you put in. 

There is a well-defined set of rules which is used internally by WPF to figure out what the real value of a DP is.  Here is a brief summary of the rules of precedence used when resolving the value of a DP (read more about it here):

  1. Property system coercion
  2. Active animations, or animations with a Hold behavior
  3. Local value
  4. TemplatedParent template
  5. Style triggers
  6. Template triggers
  7. Style setters
  8. Theme style
  9. Inheritance
  10. Default value from dependency property metadata

As that list suggests, there is a lot more going on when the value of a DP is determined than simply using the value of a field.  When you explicitly set a DP to a value (ex. this.Height = 123;), you are assigning it a “local value.”  As you can see above, a DP’s local value is the third place the system will look when resolving the property’s value. 

If the DP was registered with a callback to coerce the value to which it is set, the value returned by the callback is returned the next time you access the property.  If the DP is being animated, or was animated by an Animation which “holds” its value after it completes, the Animation’s value is returned.  If neither of those conditions is met, the DP will resolve to the value which you assigned to the property (the local value).  Failing that, the DP resolution keeps walking down that list looking for an applicable value to use.  If it reaches the end of the list and discovers that the DP was not registered with a default value, then the property’s getter returns null or zero (which are the default values for a reference type or value type, respectively).

On a side note, this explains how a trigger is able to “magically” revert the value of a DP back to the original value, once the trigger is no longer active.  Since the value applied by a trigger is part of the value resolution algorithm, as soon as a trigger stops applying a value to a DP, the DP’s value is taken from somewhere further down the list.  The DP’s value is never actually reverted, because it does not have a value in the first place!

Remember, a DP never really “has” a value…its value depends on various external factors.  That’s why they are called dependency properties.

In my next post we take a look at an example of the DP value resolution process being used, to gain a clearer understanding of how it works.

7 Responses to Demystifying dependency properties

  1. arkhivania says:

    Thanks, Josh. I have some troubles with UserControl dependency property declaration of arrays. There is inner trouble in WPF. It’s ok when i declare Collection instead.

  2. […] demystification of dependency properties In my previous blog post we examined how a dependency property can be given a value by multiple entities, but its actual […]

  3. Anonymous says:

    This is great. Thanks a lot for this kind of post which explains the fundamentals. Please keep the good work ….

  4. Anonymous Coward says:

    Thanks for the great post!

  5. Jeremy says:

    Great, thanks for the explanation!

  6. […] is ‘HoldEnd.’  Since only a dependency property (DP) can be animated in WPF, and the DP value resolution algorithm treats an animation’s value as a higher priority source than a local value, if you try to set […]

  7. […] a grouped ICollectionView has its IsSelected property set to true, as a local value.  According to the rules of dependency property value resolution, local values take precedence over the value provided by a binding.  So, the binding established […]