Page 1 of 2
Learn how dependency properties really work by creating a custom dependency property
One of the great mysteries of WPF is the strangely named "Dependency Properties".
The main reason that they are a mystery is that they are usually explained in very complicated situations with so much extra going on that it can be difficult to work out what is special about dependency properties and what belongs to some other part of WPF.
So let's see if we can simplify it without losing the essential nature of the idea.
Before going into dependency properties it's worth a quick example of how standard, or CLR (Common Language Runtime), properties work because they play an important role in using dependency properties.
In the days before dependency properties CLR properties were the only sort of properties available but over time the facilities available to implement them have been extended to make things easier.
If you want to define a CLR property then the simplest way is to use the property get set accessor declaration.
For example, to add a property called MyProp of type double to a class you would use:
public class MyClass
private double _MyProp = 0;
public double MyProp
_MyProp = value;
The set is called when the property is assigned to and the get is called when it is accessed.
Notice the use of the private _MyProp to store the value of the property between uses - this is referred to as "backing" the property with a private variable.
You can also, and often would, use multiple instructions within the get and set accessors to validate or transform the property value - this is the whole point of using a property rather than just exposing a public variable as a field.
Notice also that there are other ways of backing the property, you could store the value in a file or create it using a random number generator. As long as you come up with a suitable way of implementing a get and set function then you can do what ever you want.
Of course the get and set have to work in a way that is compatible with assignment and the set has to accept a parameter called value and the get has to return a result of the correct type.
The key idea behind dependency properties is continuing the upgrade of the idea of a property from a field to a get/set method based property to an object based property.
The CLR property replaces a simple public field by a pair of methods - the set and the get. The next logical step is to create object based properties. That is create a class called ObjProp say and give this the necessary methods and get/set assignment semantics to work as a property.
In this case you could create a property something like:
ObjProp MyProp=new ObjProp(type);
where the type parameter specified the type of the property.
Following this line of reasoning you could now create a framework that supported the way the ObjProp objects behaved. For example, assigning to an ObjProp would store the value of the property and so on. In addition, because each property was an object you could provide sophisticated facilities such as reacting to events on other objects and being able to generate events when the property changes.
Making properties object-based is a good idea but it isn't something to be undertaken lightly - it’s a big job - but the good news is you don't have to because this dependency property do exactly this.
That is, WPF's dependency properties are object-based properties that have lots of additional features and behaviors over and above basic CLR properties.
Why use dependency properties?
What do you get extra with Dependency properties?
If you have used WPF controls you will know that most of the properties that they support are dependency properties and you will also probably know the sorts of things you can do with them.
The most obvious special feature of a dependency property is that it can join in with data binding. That is, a dependency property can be linked to another property such that a change in the value of one changes the other.
Notice that this sort of behaviour can be achieved using OnChange event handlers but databinding is completely automatic and doesn't require you to enable or handle events of any kind. In most cases if your purpose is to link two or more properties then data binding is the way to go.
In addition to databinding Dependency properties have other features - as the documentation says:
support for value expressions, property invalidation and dependent-value coercion, default values, inheritance, data binding, animation, property change notification, and styling.
All of these are created by virtue of the object nature of a dependency property, i.e. a dependency property is an object of type Dependency-Property that engages in all of the above behaviors.
Each of these behaviors could occupy a complete article in its own right so to make things simpler let’s concentrate on data binding in the examples.
Dependency Property Basics
Now that we know the basic principle of the dependency property - it's an object oriented property - we can try creating a custom dependency property
The first complication is that we can't just create an instance of DependencyProperty the framework needs to know about it to allow it to take part in the common behaviours.
The solution employed by its designers is to use a static method of Dependency property to create an instance and register it:
public static readonly
DependencyProperty MyDPProperty =
The method call returns a DependencyProperty object set up to store a value of type double, with name MyDP and to act as a property belonging to MyClass.
This is how all dependency properties are created and they have to be public static readonly fields.
The reason is that the property belongs to the class and it’s the implementation that sorts out the instance being used. That is there is only one property object shared among all of the instances of the class that uses it. Which particular instance value the property is working with is determined by "this" at runtime.
There are a number of overloaded Register methods but at the very least you have to specify:
- the name of the property as a string "MyDP" in the example
- the type of the property typeof(double) in the example
- the type of the class the property belongs to typeof(MyClass) in the example.
Notice that the static readonly field is generally given the same name as the property but with "Property" tagged on.
Also notice that there are now two ways of referring to the property either by its name i.e. MyDP or by the variable MyDPProperty. You can also register a range of metadata values and callbacks but this is the minimum you need to create a custom dependency property.
Next we need the details of the class that the property belongs to. It can't be any class. It needs to inherit the methods needed to work with a dependency property and this means it has to inherit from DependencyObject or one of its descendants.
As C# only supports single inheritance you can see that this is quite a restriction and it is important that you choose the correct class to inherit from if you also want properties and methods of a particular control.