WPF For WinForms (and MFC) Developers, Part 4

January 19, 2011

2 comments

Previous posts in this series:

In previous posts, I introduced WPF and XAML. XAML is a declarative, neutral language that fundamentally allows creating objects and setting properties. But what about properties? How are they implemented in WPF? Is it the customary private field access (plus maybe validation), or maybe it’s something else? And if it’s something else, then what is it and why?

Properties

Perhaps it helps to cover some basics first. What are properties in .NET? Properties are a kind of “syntactic sugar”, meaning they are a nice way to call methods – two at most: set and get. There’s really nothing in this definition that requires a property to hide a private field. That’s an implementation detail the property user does need to concern herself with.

The “classic” (and easiest) implementation for a property is undoubtedly a private field wrapping like so:

public class Person {

   private string _firstName;

 

   public string FirstName {

      get { return _firstName; }

      set { _firstName = value; }

   }

}

 

That seems perfectly reasonable. We can add some validation logic to the setter, like so:

set {

   if(string.IsNullOrWhiteSpace(value))

      throw new ArgumentException("name cannot be empty");

   _firstName = value;

}

 

That’s fine for many scenarios. But sometimes it’s simply too simple.

For example, suppose we wanted to bind the above property to some control in our UI. How would we do that? Data binding may seem like “magic”, but there are no rabbits in the computer. When a bound property changes, this change must be somehow broadcasted to whoever is interested. In the above implementation that will not happen. So, this property cannot be successfully data bound.
Let’s consider another facet of this. Suppose we have a Button class (e.g. in WinForms). How many properties does it have? The simple answer is “many”. I think about 50 or so (didn’t count them). Now suppose each property is backed by a private field like the example above. That means, that when a button is created, at least 50 fields come into existence, taking up memory, while usually we change very few properties, leaving most of them with their default values.

Now imagine using dozens of buttons and other controls (list box, check box, picture box, whatever) in one Form/Window: They become memory hogs – causing more frequent garbage collection and generally larger working set. This is unfortunate, as only a small number of properties are actually modified, leaving most with the default value, but still taking up memory.

These (and other) reasons led to the development of dependency properties.

Dependency Properties

So, what are dependency properties? It’s an infrastructure designed to support change notifications, validation, all while conserving memory – properties that don’t change – don’t need storage space.

the infrastructure is based upon the DependencyProperty class, along with the DependencyObject class, which is a required base class for any entity that wants to define dependency properties.

So, how does this look? Let’s change the Person declaration to use a dependency property:

public class Person : DependencyObject {

   public string FirstName {

      get { return (string)GetValue(FirstNameProperty); }

      set { SetValue(FirstNameProperty, value); }

   }

 

   public static readonly DependencyProperty FirstNameProperty =

       DependencyProperty.Register("FirstName", typeof(string), typeof(Person), new UIPropertyMetadata(string.Empty));

}

 

We can declare a dependency property in Visual Studio pretty quickly with the “propdp” code snippet (type “propdp” without the quotes and press TAB twice). What does this code mean?

First we see a “regular” property declaration, but its implementation (detail) is using the GetValue and SetValue methods inherited from DependencyObject. So, to the outside world (outside the Person class), FirstName appears as just a regular property, because a property is just syntactic sugar for two method calls behind the scenes (get_FirstName and set_FirstName in this case). But note that there is no private field anywhere.

The “real” declaration is with that public static field of type DependencyProperty named FistNameProperty that “registers” the property, supplying its name, its type, its owner’s type and a set of metadata (here just the property’s default value). The last setting means that unless someone changes the FirstName of some Person, its default value will be taken from the same location (defined by the registering of the dependency property).

Realistically, you would not implement a data object (such as Person) with dependency properties. First, it creates a dependency (pun intended) on the WPF assemblies – for no good reason – maybe your data objects already exist. Secondly, you must inherit from DependencyObject, which means you can’t inherit from anything else, which is pretty limiting.

But for elements and controls in the WPF world this is not a concern, as all elements inherit from DependencyObject indirectly, so elements use dependency properties all the time. In fact, all properties that we used so far (Background, Fill, Title, etc.) were all dependency properties. We accessed them (in XAML or in code) in the usual way, because the actual implementation is hidden behind the property.

What about change notifications? It turns out that we can supply more parameters to the Register method and provide a change notification delegate and validation delegate (if needed), so we are fully covered and ready for things like data binding. It’s important to note that validation code should not ever be placed inside the setter, because code using the property may elect to “skip the middleman” (the property wrappers) and call SetValue directly (in fact, the XAML parser does that).

Is that all? Not quite.

Why are they called “Dependency”?

Good question. The property value “depends” on a current “supplier” of a value. What does this mean? Suppose I create several TextBlock objects like so:

 

<Window x:Class="WpfApplication2.MainWindow"
       xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
       xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
       Title="MainWindow" Height="350" Width="525">
    <StackPanel>
        <TextBlock Text="Some text 1" />
        <TextBlock Text="Some text 2" />
        <TextBlock Text="Some text 3" />
        <TextBlock Text="Some text 4" />
    </StackPanel
>
</
Window
>

We’ll see four text blocks rendered with the default font properties registered in the static constructor of the control. Let’s take the FontSize property as an example. Its default value is 12 as we can examine this in code by reading the FontSize property of one of the text blocks. Now, let’s change the FontSize property of the Window instance to 30:

<Window x:Class="WpfApplication2.MainWindow" …
       Title="MainWindow" Height="350" Width="525"
        FontSize="30"
>

You’ll notice all the text blocks rendered in font size of 30!

Why? Because of property value inheritance. The FontSize property has been “inherited”, not in the object oriented sense (as TextBlock does not derive from WIndow or vice versa) but in the visual tree sense. This means that the inherited value takes precedence over the default value. The default value is not overwritten, and if the inherited value “disappears” somehow, the default value will again be used. Not all dependency properties have value inheritance – only those that are registered as such (with the FrameworkPropertyMetadataOptions.Inherits flag)

Let’s continue and do one more change: Let’s change the font size of one of the text blocks to 20:

<TextBlock Text="Some text 1" />
<TextBlock Text="Some text 2"  FontSize="20"/>
<TextBlock Text="Some text 3" />
<TextBlock Text="Some text 4"
/>

Now what do we find? The changed text block uses a font size of 20. Again, this means that the local value (20) has higher precedence than the inherited value (30).

What this means is that a dependency property can have many “values”, but only the highest property value is reported by calling GetValue. When the highest priority “provider” “disappears”, the next priority value becomes the current property value. This allows for (e.g.) animation, which changes a property as long as the animation is active (animation is the highest precedence provider); when the animation is removed, the property reverts to its previous value (depending on the highest priority provider at that time).

Summary

Dependency properties is a mechanism that provides for many of its abilities: data binding, property value inheritance and animation, to name a few obvious ones. Dependency properties are used in Silverlight as well (a bit less powerful) and even the Workflow Foundation (again, less powerful and adjusted to that domain).

In the next part, we’ll take a look at a special kind of dependency properties that are surprisingly useful – attached properties.

Add comment
facebook linkedin twitter email

Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

2 comments

  1. JulesMarch 14, 2011 ב 00:18

    Hi,

    I’ve enjoyed your series of posts regarding WPF. You mentioned at the end of this article that you’re planning another instalment. Do you still plan to write it?

    Thanks

    Reply
  2. pavelyMarch 14, 2011 ב 06:50

    Hi,

    I’m glad you like it.
    I did post part 5 and planning to do more as time permits…

    Pavel

    Reply