The Ins and Outs of Dependency Properties and Routed Events in WPF

XAML, one of the most important pieces in the Windows Presentation Foundation (WPF) puzzle, is merely another way to describe your intent to the computer. In fact, the XAML you write can almost always be written in VB.NET or C#. For instance, you could create a button using the following XAML code:

<Grid Name="myGrid">
   <Button Width="200" Height="50">Sample Button</Button>
</Grid>

Alternatively, you could achieve the same effect using the following C# code:

Button btn  = new Button();
btn.Content = "Sample Button";
btn.Width   = 200;
btn.Height  = 50;

myGrid.Children.Add(btn);

Either of the above will produce an output similar to Figure 1.

Figure 1. Output from XAML and C# Code for Creating a Button

As you can see, the C# code seems to equate XAML’s element names to classes, and its attributes to properties of those classes. Anywhere it encounters nested elements, some mechanism in C# adds them either as children or as content of the outer element. This seems like a very linear transformation of the code from XAML to C#.

Now, to complicate this a little bit. Suppose you have some nesting of elements. Consider the following XAML:

<Grid Name="myGrid" Margin="20">
   <TextBlock>
      Sample Text outside the ItemsControl block
   </TextBlock>
   <ItemsControl Foreground="Red" VerticalAlignment="Center">
      <TextBlock>Sample Text without foreground</TextBlock>
      <TextBlock Foreground="Blue">
         Sample Text with foreground
      </TextBlock>
   </ItemsControl>
</Grid>

As you can see, there are three TextBlocks. Two of them have no ForeGround specified, but one of those two is nested inside an ItemsControl element that does have a ForeGround specified. If you run this application, it produces the output in Figure 2.

Figure 2. Application with Nested Elements

The first TextBlock is black because it has no ForeGround set on it. But by that argument, the second TextBlock should also be black. Curiously enough, it is getting its ForeGround from the element in which it is nested. There is something behind the scenes that is setting the second TextBlock’s ForeGround to red. That same mechanism is probably also trying to set the ForeGround of the third TextBlock to red, but the third TextBlock has chosen to ignore that and instead specify its own ForeGround to blue. Clearly, this isn’t a simple linear transformation to C#.

However, before you accept that conclusion, try writing this code in C#. If you had to write a simple linear transformation of the XAML to C#, the code would look a bit like this:

TextBlock firstTextBlock = new TextBlock();
firstTextBlock.Text      = "Sample Text outside the ItemsControl
                            block";

ItemsControl itc      = new ItemsControl();
itc.Foreground        = Brushes.Red;
itc.VerticalAlignment = VerticalAlignment.Center;

TextBlock secondTextBlock = new TextBlock();
secondTextBlock.Text      = "Sample text without foreground";
itc.Items.Add(secondTextBlock);

TextBlock thirdTextBlock  = new TextBlock();
thirdTextBlock.Foreground = Brushes.Blue;
thirdTextBlock.Text       = "Sample Text with foreground";
itc.Items.Add(thirdTextBlock);

myGrid.Children.Add(firstTextBlock);
myGrid.Children.Add(itc);

Now, when you run the application, you’d probably be shocked to see that the output looks like Figure 3.

Figure 3. Linear Transformation of the XAML to C#

So the linear transformation of XAML to C# seems to produce the same results? Not one line of code above seems to set secondTextBlock.ForeGround to its parent’s ForeGround. Yet the ForeGround of the second TextBlock is red, not the default black. Who is setting the ForeGround of the second TextBlock? The answer is the WPF runtime is setting ForeGround, because ForeGround is a dependency property.

In fact, the above example is just one of the ramifications of not fully understanding dependency properties (in this case, an attached property).

Dependency Properties Explained

A dependency property is a property of an element that depends on a number of things outside the element. In WPF, if you want properties on your custom elements (visual or otherwise) to support things such as value expressions, property invalidation, per-type default values, inheritance, data binding, animation, and styling, you need to use dependency properties. Thus, dependency properties are one of the most important concepts within WPF.

So, how can you author your own dependency property? When writing a Windows or ASP.NET control, you would typically write a property to represent ForeGround, in a manner similar to the following:

public class MyCustomControl : {..some base class..}
{
   private Brush _foreGround;

   public Brush ForeGround
   {
      get { return _foreGround; }
      set { _foreGround = value; }
   }
}

Writing a dependency property for a WPF element is a bit different. If you had to author a dependency property to represent foreground color on a custom element, it would look like this:

public class MyCustomElement : Control
{
   public MyCustomElement() : base() { }
   public Brush ForeGround
   {
      get { return (Brush)this.GetValue(ForeGroundProperty); }
      set { this.SetValue(ForeGroundProperty, value); }
   }
   public static readonly DependencyProperty ForeGroundProperty =
      DependencyProperty.Register(
         "ForeGround", typeof(Brush), typeof(MyCustomElement));
}

As you can see, there are two main steps involved in creating a dependency property:

  1. Create a property called ForeGround, just as you would in a Windows or ASP.NET control.
  2. Call two curious methods, SetValue and GetValue, in which you pass in a public static readonly variable called ForeGroundProperty. This public variable is of type DependencyProperty, and the base class Control inherits from DependencyObject, which includes the methods SetValue and GetValue.

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read