WPF Tutorial: Dependency Properties

Hello all, I know I’ve been away for a bit but now I’m back with a sweet coding tutorial. I’ve been doing a lot of WPF lately for my current job at InterKnowlogy, so I decided to write up a quick overview of two new and very important UI features of .NET 3.5 called Dependency Properties and Data Binding. If you still haven’t played around with WPF yet, I definitely recommend that you take a look at some of the new features that it offers. All I will say is that after using WPF, I don’t think I will be going back to WinForms any time soon.

So, let’s get started. First of all, the idea behind the addition of Dependency Properties in WPF was to be able to allow a developer to do 4 things:

  1. Data Bind the control to a specific property of an object in the data model (more on that later),
  2. Create Attached Properties, which allow for child elements in XAML to specify values for properties defined in a parent element,
  3. Define Metadata for a property, which allows a developer to set a default value for a property (among other things), and finally,
  4. Handle Property Validation natively.

There are also some other things that Dependency Properties allow you to do, such as creating Routed Events, but that is a topic for another time.

So, as you can see, the concept of Dependency Properties is a huge part of WPF that not only drives its core functionality, but also helps stand it apart from WinForms in a big way. Any UI element that inherits from DependencyObject allows that element to take part in WPF’s Property System services. This helps make controls aware of the dependencies that exist between itself and a given property, as well as allowing properties to trigger actions on the element based on changes to that property. Every WPF control (such as a Button, Panel, MediaElement, etc) inherits from FrameworkElement, which in turn is a UIElement, which eventually extends DependencyObject.

Ok, let’s get into an example so you can see Dependency Properties at work. First of all, I created a quick WPF Application that consists of a ComboBox to display a list of Ninja objects, and a Custom Control called NinjaControl that holds two TextBoxes and a TextBlock to display the details about the currently selected Ninja.

Figure 1

Figure 1

Figure 2

Figure 2

In my code, you can see a quick example of some Attached Properties of the Grid element at work, Grid.Row and Grid.Column. Although Grid.Column isn’t actually present in my code, I have those properties being set by styles that are defined in the NinjaControl’s Grid.Resources element. Regardless, you can see that the Row property doesn’t actually exist in a Label or a TextBox control. Instead, it is an Attached Property of the Grid control that tells the Grid where to place the element.

By exposing a property as an Attached Property, you reduce the number of properties that a potential child element would need to expose, which would in turn tightly bind that control to that specific parent element. For example, it wouldn’t make sense to have every control to specify a Row and Column property, since they may not even be contained within a Grid control. A Button has no idea what a Grid is, but if it happens to be contained within a Grid, then it gains access to the Grid control’s Row and Column Attached Properties to let the Grid handle where the Button should be placed.

Next, we will create a Ninja class with Name, Specialty, and Description properties, and then Data Bind a list of Ninja objects to the NinjasComboBox. To do this, we need to set the ItemsSource property of the NinjasComboBox to a list of Ninja objects. Finally, all we need to do is set the DisplayMemberPath of the ComboBox to “Name” so that the combo box will display the name of each of the Ninja objects in the Ninja list.

Figure 3

Figure 3

Ok, now we need to create a Dependency Property for the NinjaControl to allow us to data bind to the currently selected Ninja in the ComboBox. In here, we will create a new static readonly DependencyProperty called CurrentNinjaProperty by using the DependencyProperty’s static Register() method.

Figure 4

Figure 4

Making your DependencyProperty public, static, and readonly is important for two reasons. First of all, I had originally believed that making it a public static variable was required for XAML to access the DependencyProperty. However, I found that declaring it as static didn’t have an effect on the expected behavior. If anyone else knows more on this, please let me know. Secondly, declaring your DependencyProperty as readonly allows it to only be instantiated once, and prevents others from re-registering it in their own classes, like this:

Figure 5

Figure 5

Yeah, that would be bad for obvious reasons.

Anyway, we can also see some of the key features at work in the registration of our DependencyProperty, such as the addition of a FrameworkPropertyMetadata object as a parameter, which allows me to set metadata values for the DependencyProperties, such as a default value for the property, a callback for when the property has changed, and whether or not the DependencyProperty allows data binding. From msdn:

“Note that the IsNotDataBindable property is set to true specifically for properties that should not support data binding, despite being read-write properties. The expectation is that in most cases where a dependency property is declared, data binding is desired, because data binding is one of the key scenarios where a dependency property is useful… Read-only dependency properties (i.e. prosperties without a setter) do not support data binding (because they have no setter that can apply changed values), but will still report false for IsNotDataBindable… To determine whether a given dependency property permits data binding, you should usually check IsDataBindingAllowed instead.”

Most importantly, you can see that the FrameworkPropertyMetadata object allows us to set a PropertyChangedCallback, which I’ve set to the static OnCurrentNinjaChanged() event handler. However, the trick inside this callback is that since the method itself is static, it may still need to access instance variables, such as DataContext in our case. This is why the callback method is passed a reference to the DependencyObject instance, which is actually our NinjaControl object. From this, we can re-set the DataContext of our control, and therefore, update the bindings on all of the data-bound objects. Here is the code for the data bindings, as well as the finished product:

Figure 6

Figure 6

Figure 7

Figure 7

As a final note, I’d like to add that placing code in the property getters/setters for Dependency Properties is a bad idea, because they are basically just wrappers to provide a familiar syntax to the consumer of your class. XAML doesn’t use the property getter/setter when it’s data-bound. Instead, it goes straight into the static Dependency Property and figures out where to go from there.

Resources:

If you like this blog please take a second and subscribe to my rss feed

Tags: , , ,

Comments: 4 comments

All the fields that are marked with REQ must be filled

  • Mike Gromer
    July 20th, 2008 at 9:17 pm

    Mike Gromer > Chuck Norris

  • Rex
    July 23rd, 2008 at 9:30 am

    Tetsutaro Mameda > *

    I need to sit down and mess with WPF, it seems pretty cool but I haven’t had the motivation to do it (aka been forced to learn it for a project).

  • Ryan Abreu
    July 23rd, 2008 at 10:57 am

    I think I’ll be doing a few more WPF tutorials over some of the basic concepts, partly so that I’ll be able to solidify them a bit more in my head, and hopefully to inspire some outsiders into moving to WPF, or at least trying it out. I know it took me a few tries before I started loving it.

  • Senor Reed
    July 23rd, 2008 at 3:24 pm

    Dang, awesome article. If all websites had articles as great as this one, I’d do nothing but read blogs all day long. Ryan, you have been my hero in the past and yet now, you seem even more of a hero to me than ever. In many ways I long for simpler times where I could sit down and soak up your illustrious aura of brilliance.

    And I’m sorry Gromer but Tets and Chuck could both kick your butt using only each other’s pinkies as a weapon.

Leave a reply

Name (Req)

E-mail (Req)

URI

Message