Implement dependency properties

May include but is not limited to: enabling data binding and animation, property metadata, property change callbacks

WPF adds a new concept to the classic .NET property world, namely dependency properties. They introduce some nice new features such as property value inheritance and change notification. You can imagine that most of the WPF properties are dependency properties.

Like almost anything else, dependency properties are coming in multiple variations. The first is a “simple” dependency property, and the second is an attached dependency property. More info about the latter is in the end of this post.

What do we need to define a classic dependency property (that is not an attached one)? Three things:

  • defining the property
  • registering it
  • wrapping it within a normal .NET property

Well, that doesn’t sound like a big issue, so let’s define one!

First we need to define the property – in the class we’ll use it in. To do so, we need to add a static field of type DependencyProperty (this field might be shared with other elements, so it’s a good point to define it as static). Also, you need to define the field with the readonly keyword, so it can only be set in a static constructor. The whole code might look as follows:

public static readonly DependencyProperty ColorProperty;

Now you need to register it with the class you’d like to use. We created a static readonly field, so the best way to set it is a static constructor. To register a dependency property, you can define five things:

  • Property name
  • Data type used
  • Owner type
  • A FramewokrPropertyMetadata object – optional
  • A validation callback – optional

So working with the previous example, you could do something like this in the static constructor:

ColorProperty = DependencyProperty.Register(“Color”, typeof(Color), typeof(FrameworkElement));

The last two things are FrameworkPropertyMetadata and the validation callback – they deserve some explanation. The FrameworkPropertyMetadata class has some Boolean flags you can set, and they can indicate a bunch of things, like if the property affects the rendering of the item, is it inheritable by child properties, a default value, etc. An interesting feature is that it lets you define two callback methods – CoerceValueCallback and PropertyChangedCallback. More info on them later.

A validation callback is a bit limited callback method you can define in the DependencyProperty.Register method. Because it knows of only the value to be validated, and not the context, you can do some basic validation by it (like for example the value isn’t negative). But you can’t check if the value is bigger than another value in the same object. That’s what Coercion callbacks are for.

OK, the last thing to do when you work with a normal dependency property is to wrap it within a normal .NET property. You should use the GetValue and SetValue methods, and never place any validation logic inside your property getters and setters, because they can be bypassed by WPF. So to stick with our color example, here’s what you’d do:

public Color Color
{
get { return (Color) GetValue(ColorProperty);}
set { SetValue(ColorProperty, value); }
}

And you’re done. I told you in the very beginning that there are two types of dependency properties. That was the first one, now let’s see the second. It’s called an attached dependency property, and the main difference is that it’s an attached property.

There isn’t much difference between defining an attached and a normal dependency property. You define it as a static readonly field, but you use the RegisterAttached method of the DependencyProperty class. You define static getter and setter methods, with the name GetPropertyName and SetPropertyName, as follows:

public static Color GetColor(UIElement element)
{
return (Color) element.GetValue(UIElement.Color);
}
public static void SetColor(UIElement element, Color value)
{
element.SetValue(UIElement.Color, value);
}

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s