Demystifying Silverlight Dependency Properties

I have the opportunity to teach a lot of people about Silverlight (among other technologies) and one of the topics that definitely confuses people initially is the concept of dependency properties. I confess that when I first heard about them my initial thought was “Why do we need a specialized type of property?” While you can certainly use standard CLR properties in Silverlight applications, Silverlight relies heavily on dependency properties for just about everything it does behind the scenes. In fact, dependency properties are an essential part of the data binding, template, style and animation functionality available in Silverlight. They simply back standard CLR properties. In this post I wanted to put together a (hopefully) simple explanation of dependency properties and why you should care about them if you’re currently working with Silverlight or looking to move to it.

 

What are Dependency Properties?

XAML provides a great way to define layout controls, user input controls, shapes, colors and data binding expressions in a declarative manner. There’s a lot that goes on behind the scenes in order to make XAML work and an important part of that magic is the use of dependency properties. If you want to bind data to a property, style it, animate it or transform it in XAML then the property involved has to be a dependency property to work properly. If you’ve ever positioned a control in a Canvas using Canvas.Left or placed a control in a specific Grid row using Grid.Row then you’ve used an attached property which is a specialized type of dependency property. Dependency properties play a key role in XAML and the overall Silverlight framework.

Any property that you bind, style, template, animate or transform must be a dependency property in Silverlight applications. You can programmatically bind values to controls and work with standard CLR properties, but if you want to use the built-in binding expressions available in XAML (one of my favorite features) or the Binding class available through code then dependency properties are a necessity. Dependency properties aren’t needed in every situation, but if you want to customize your application very much you’ll eventually end up needing them. For example, if you create a custom user control and want to expose a property that consumers can use to change the background color, you have to define it as a dependency property if you want bindings, styles and other features to be available for use. Now that the overall purpose of dependency properties has been discussed let’s take a look at how you can create them.

Creating Dependency Properties

When .NET first came out you had to write backing fields for each property that you defined as shown next:

Brush _ScheduleBackground;

public Brush ScheduleBackground
{

    get { return _ScheduleBackground; }
    set { _ScheduleBackground = value; }

}

Although .NET 2.0 added auto-implemented properties (for example: public Brush ScheduleBackground { get; set; }) where the compiler would automatically generate the backing field used by get and set blocks, the concept is still the same as shown in the above code; a property acts as a wrapper around a field. Silverlight dependency properties replace the _ScheduleBackground field shown in the previous code and act as the backing store for a standard CLR property.

The following code shows an example of defining a dependency property named ScheduleBackgroundProperty:

public static readonly DependencyProperty ScheduleBackgroundProperty =
  DependencyProperty.Register("ScheduleBackground", typeof(Brush),
  typeof(Scheduler), null);

 

Looking through the code the first thing that may stand out is that the definition for ScheduleBackgroundProperty is marked as static and readonly and that the property appears to be of type DependencyProperty. This is a standard pattern that you’ll use when working with dependency properties. You’ll also notice that the property explicitly adds the word “Property” to the name which is another standard you’ll see followed. In addition to defining the property, the code also makes a call to the static DependencyProperty.Register method and passes the name of the property to register (ScheduleBackground in this case) as a string. The type of the property, the type of the class that owns the property and a null value (more on the null value later) are also passed. In this example a class named Scheduler acts as the owner.

The code handles registering the property as a dependency property with the call to Register(), but there’s a little more work that has to be done to allow a value to be assigned to and retrieved from the dependency property. The following code shows the complete code that you’ll typically use when creating a dependency property. You can find code snippets that greatly simplify the process of creating dependency properties out on the web. The MVVM Light download available from http://mvvmlight.codeplex.com comes with built-in dependency properties snippets as well.

public static readonly DependencyProperty ScheduleBackgroundProperty =
  DependencyProperty.Register("ScheduleBackground", typeof(Brush),
  typeof(Scheduler), null);

public Brush ScheduleBackground
{
    get { return (Brush)GetValue(ScheduleBackgroundProperty); }
    set { SetValue(ScheduleBackgroundProperty, value); }
}

The standard CLR property code shown above should look familiar since it simply wraps the dependency property. However, you’ll notice that the get and set blocks call GetValue and SetValue methods respectively to perform the appropriate operation on the dependency property. GetValue and SetValue are members of the DependencyObject class which is another key component of the Silverlight framework. Silverlight controls and classes (TextBox, UserControl, CompositeTransform, DataGrid, etc.) ultimately derive from DependencyObject in their inheritance hierarchy so that they can support dependency properties.

Dependency properties defined in Silverlight controls and other classes tend to follow the pattern of registering the property by calling Register() and then wrapping the dependency property in a standard CLR property (as shown above). They have a standard property that wraps a registered dependency property and allows a value to be assigned and retrieved. If you need to expose a new property on a custom control that supports data binding expressions in XAML then you’ll follow this same pattern. Dependency properties are extremely useful once you understand why they’re needed and how they’re defined.

Detecting Changes and Setting Defaults

When working with dependency properties there will be times when you want to assign a default value or detect when a property changes so that you can keep the user interface in-sync with the property value. Silverlight’s DependencyProperty.Register() method provides a fourth parameter that accepts a PropertyMetadata object instance. PropertyMetadata can be used to hook a callback method to a dependency property. The callback method is called when the property value changes. PropertyMetadata can also be used to assign a default value to the dependency property. By assigning a value of null for the final parameter passed to Register() you’re telling the property that you don’t care about any changes and don’t have a default value to apply.

Here are the different constructor overloads available on the PropertyMetadata class:

PropertyMetadata Constructor Overload

Description

PropertyMetadata(Object)

Used to assign a default value to a dependency property.

PropertyMetadata(PropertyChangedCallback)

Used to assign a property changed callback method.

PropertyMetadata(Object, PropertyChangedCalback)

Used to assign a default property value and a property changed callback.

 

There are many situations where you need to know when a dependency property changes or where you want to apply a default. Performing either task is easily accomplished by creating a new instance of the PropertyMetadata class and passing the appropriate values to its constructor. The following code shows an enhanced version of the initial dependency property code shown earlier that demonstrates these concepts:

public Brush ScheduleBackground
{
    get { return (Brush)GetValue(ScheduleBackgroundProperty); }
    set { SetValue(ScheduleBackgroundProperty, value); }
}

public static readonly DependencyProperty ScheduleBackgroundProperty =

DependencyProperty.Register("ScheduleBackground", typeof(Brush),
  typeof(Scheduler), new PropertyMetadata(new SolidColorBrush(Colors.LightGray),
  ScheduleBackgroundChanged));

private static void ScheduleBackgroundChanged(DependencyObject d,
  DependencyPropertyChangedEventArgs e)
{
    var scheduler = d as Scheduler;
    scheduler.Background = e.NewValue as Brush;
}

The code wires ScheduleBackgroundProperty to a property change callback method named ScheduleBackgroundChanged. What’s interesting is that this callback method is static (as is the dependency property) so it gets passed the instance of the object that owns the property that has changed (otherwise we wouldn’t be able to get to the object instance). In this example the dependency object is cast to a Scheduler object and its Background property is assigned to the new value of the dependency property. The code also handles assigning a default value of LightGray to the dependency property by creating a new instance of a SolidColorBrush.

To Sum Up

In this post you’ve seen the role of dependency properties and how they can be defined in code. They play a big role in XAML and the overall Silverlight framework. You can think of dependency properties as being replacements for fields that you’d normally use with standard CLR properties. In addition to a discussion on how dependency properties are created, you also saw how to use the PropertyMetadata class to define default dependency property values and hook a dependency property to a callback method.

The most important thing to understand with dependency properties (especially if you’re new to Silverlight) is that they’re needed if you want a property to support data binding, animations, transformations and styles properly. Any time you create a property on a custom control or user control that has these types of requirements you’ll want to pick a dependency property over of a standard CLR property with a backing field.

There’s more that can be covered with dependency properties including a related property called an attached property….more to come.

comments powered by Disqus

8 Comments

  • Hey Dan,

    I did a quick speed reading of your post, but gave up. The problem is that I have learned and forgotten this about 3 times, and unfortunately the brain in the 30s is not the brain in your 20s :-(

    Realistically the next time I will try to learn this will be when I try to write an app for Windows Phone 7 or something similar ;-) My brain will have a better chance of retaining this information if I immediately put it into practice.

    It is funny how your brain absorbs different things. With LINQ I read the original LINQ paper and it just stuck in my brain ever since; with jQuery the same. I don't know why certain technologies just seem harder to grasp. I also have this problem with XAML even though I know it is just a mapping from XML to a .NET object graph, etc. I keep reading...and forgetting :-(

    David

  • Nice intro to dependency and how and where it is used. How about a more technical article on why? I'm also interested in the overall pattern that the team used, and when/ how it should be used in application design. When you register a property it must be stored in a collection. With all these properties being set statically ( is that a word?), the collection should be a bottleneck, let alone a concurrency issue.

  • David:

    I'd agree with you in that when you're using a technology it's easier to retain information you've learned about it. If you're not currently using a particular technology and just reading about it (you don't really need it though) I personally think the brain kind of understands that it doesn't really need the information and doesn't worry about storing it as permanently. At least that's my experience. The times I've really needed to understand a technology it seems like it's a lot easier to retain. Having said that, the syntax for dependency properties isn't exactly the most straightforward which is why I have a code snippet handy to do it for me. :-)

    Dan

  • You explain the scenarios of when it is needed, but not why it is really needed ... what is the underlying technical problem that caused the creation of dependency properties in the first place?

    Also, where binding does work against a standard property, can you elaborate on where / when binding will break and the symptoms of it breaking without the use of a dependency property?

  • beameup: Actually I hope I made it clear when they're needed since it's mentioned several times that they're needed for data binding, animations, styles, etc. The Silverlight framework requires dependency properties for all of the things mentioned (binding, animation, etc.). The main reason is for registering these specialized types of properties with the framework and property change notifications. That's a framework requirement though and not something we have control over which is why I don't put a ton of detail there...it's a black box (plus the post was kept as focused as possible to help people understand how to use DPs rather than trying to cover everything and confuse people even more :-)). Here's the official description by Microsoft of dependency properties though if you're interested (http://msdn.microsoft.com/en-us/library/cc221408(VS.95).aspx):

    "The purpose of dependency properties is to provide a way to compute the value of a property based on the value of other inputs. These other inputs might include external properties such as user preference, just-in-time property determination mechanisms such as data binding and animations/storyboards, multiple-use templates such as resources and styles, or values known through parent-child relationships with other elements in the object tree. In addition, a dependency property can be implemented to provide callbacks that can propagate changes to other properties."

    As far as binding with standard properties, that's a great question and there are a few sides to the story. If you have a Customer class with a standard CLR property of FirstName then you can bind it to any control (the Text property of a TextBox for example). For data classes you typically won't use dependency properties since the properties in question simply hold the data. If you want property notification support you can enhance the set block of FirstName to notify Silverlight when the property changes so that the TextBox stays in-sync when a TwoWay binding is defined (that's where INOtifyPropertyChanged comes into play). That's one area where standard CLR properties can be used.

    The other angle is the actual properties on controls that we bind data to. While you can define a standard CLR property publicly on a control, you'd be limited as to how it could be used in XAML or through code. You couldn't use data binding expressions with it and couldn't animate, transform or style it (assuming that was needed). So, for properties exposed through custom user controls or custom controls you'll use dependency properties whenever you need to support data binding expressions, animations and the other items mentioned. There are always exceptions to the rule (read-only properties for example).

    In a nutshell, dependency properties replace fields as the backing data store for CLR properties and add additional functionality that Silverlight requires for data binding, animations, styles, templates, transforms, etc. Although they're called "Dependency Properties" I supposed you can think of them as "Dependency Fields" in a way.

    Dan

  • Last line of code
    scheduler.Background = e.NewValue as Brush;
    should be
    scheduler.ScheduleBackground = e.NewValue as Brush;

  • abap: Thanks for the feedback. That line of code is correct though since scheduler would be a control or user control that has a Background property. We're taking the value from ScheduleBackground as it changes and assigning it to Background.

    Dan

  • It gets even better.
    Wait until you're in your 50s kid. :-)

Comments have been disabled for this content.