Meet DependencyObject and DependencyProperty, the .NET Data-Binding Boosters

Wednesday Dec 13th 2006 by Chad A. Campbell
Share:

Using the DependencyObject and the DependencyProperty in conjunction enables .NET developers to expose some of the powerful features of the Windows Presentation Foundation. Learn how to implement data binding with them.

With the introduction of the .NET 3.0 Framework, Microsoft made the DependencyObject and the DependencyProperty fundamental concepts, placing them at the forefront of development. Using these two items in conjunction enables .NET developers to expose some of the powerful features of the Windows Presentation Foundation (WPF).

In the meantime, data binding has proven to be a valuable construct within the development world. This article introduces data binding and explains how it can be effectively implemented using the DependencyObject/DependencyProperty within the WPF.

What Is Data Binding?

As the name of the functionality implies, data binding is essentially a way to bind to data. Basically, you can view it as a way to create a link or a connection between a source item and a target item. The source item owns the desired information and the target item is dependent upon this information.

There are two fundamental types of data binding in Windows:

  1. OneWay mode binding via System.Windows.BindingMode.OneWay, in which one item listens to another, but the second item does not listen to first.
  2. TwoWay mode binding via System.Windows.BindingMode.TwoWay, in which the two items essentially are listening to each other.

Figure 1 illustrates the first type of data binding. The illustration may be unfair to principals, but the general idea is there. This approach automatically transfers the value of the source property to the target property. This means, if the source property changes, the target property changes. However, if the target property changes, the source property does not change.

Figure 1. Data Binding in OneWay Mode

Figure 2 illustrates the second type of data binding. Changes from one property are automatically propagated to the other property. This means if the source property changes, the target item changes. Conversely, if the target item changes, the source item changes.

Figure 2. Data Binding in TwoWay Mode

To understand the power of data binding, consider a program guide system for a television receiver. Imagine if viewers had to select "get the latest television guide" and wait for the program data to be retrieved every time they turned on their televisions? Obviously, they should not have to do that. Program guide systems automatically provide viewers with up-to-the-minute program data.

In much the same way, data binding provides a way for developers to get the most up-to-date program data automatically. Without data binding, developers essentially would have to click a "get the latest program data" button to perform a data-retrieval task.

Why Should I Care?

Utilizing the DependencyObject and DependencyProperty provides a way to retrieve values from other items dynamically at runtime. In an event-based model, a developer would have to write code to handle an event and define what should happen with the event. With the DependencyProperty, a developer can essentially bind a property to another property and the value is set dynamically at runtime as the value changes.

For illustration, picture a typical media player with a volume-control dial. Turning the dial either increases or decreases the volume. Traditionally, a developer would have to write code to set the volume as the dial turns. However, with the DependencyObject/DependencyProperty, the developer essentially can bind the value of the volume to the dial and then the volume updates automatically.

From a technical point of view, utilizing the DependencyObject and DependencyProperty objects has a number of benefits. Chiefly, using the DependencyProperty object exposes some powerful features of WPF, including but not limited to the following:

  • Animations
  • Data binding, which you now know all about
  • Metadata overrides, which let you alter behaviors derived from metadata
  • Property value inheritance, which enables you to use the value of a parent object

How Do I Do It?

To demonstrate the usefulness of data binding, consider a desired solution involving fantasy football. An important feature of fantasy football is the ability to view player profiles. The example in this article demonstrates how to provide this feature with data binding.

Before actually binding to a source, the source must be defined. For the purpose of this example, the source will be defined using the DependencyObject/DependencyProperty approach. However, data source objects do not need to be DependencyObject instances. In fact, WPF is very flexible and supports data-binding in several other forms including:

  • Data exposed through ADO.NET
  • Traditional CLR objects
  • XML data

The following code defines a typical object with three properties, representing a football player:

  • FirstName: The player's first name
  • LastName: The player's last name
  • Position: The player's position on the team (in other words, "QB", "WR", "TE", and so forth)
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
namespace Source_Code
{
   public class Player : DependencyObject
   {
      public static DependencyProperty FirstNameProperty =
         DependencyProperty.Register("FirstName", typeof(string),
                                     typeof(Player));
      public string FirstName
      {
         get { return (string)GetValue(FirstNameProperty); }
         set { SetValue(FirstNameProperty, value); }
      }
      public static DependencyProperty LastNameProperty =
         DependencyProperty.Register("LastName", typeof(string),
                                     typeof(Player));
      public string LastName
      {
         get { return (string)(GetValue(LastNameProperty)); }
         set { SetValue(LastNameProperty, value); }
      }
      public static DependencyProperty PositionProperty =
         DependencyProperty.Register("Position", typeof(string),
                                     typeof(Player));
      public string Position
      {
         get { return (string)(GetValue(PositionProperty)); }
         set { SetValue(PositionProperty, value); }
      }
   }
}

The code sample displays something slightly different from a traditional .NET object. First, the Player object derives from the DependencyObject. This is necessary to implement DependencyProperty properties. Declaring an object as a DependencyObject informs the system that the object wants to utilize the built-in features defined earlier.

Second, several of the properties are defined as DependencyProperty items. When providing a DependencyProperty to back a property, the property is exposed to the dependency system, which automatically gives the powerful features defined previously. You can utilize both traditional properties and DependencyProperty items within a DependencyObject. However, only the DependencyProperty items will gain the pre-defined built-in features.

After defining the source (the Player object), the target item can bind, or interact, with the source. At this point, the target has not been defined. This example creates a simple player profile page, which will display a player's first name, last name, and position. Here is the XAML code for the window that will display this information:

<Window x:Class="Source_Code.Profile"
   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   xmlns:AppCode="clr-namespace:Source_Code"
   Title="Player Profile" Height="300" Width="300"
   >
   <StackPanel Name="ProfileStackPanel" Orientation="Horizontal">
   <TextBlock Name="LastNameTextBlock" />
   <TextBlock Text=", " />
   <TextBlock Name="FirstNameTextBlock" />
   <TextBlock Text=" - " />
   <TextBlock Name="PositionTextBlock" />
   </StackPanel>
</Window>

Placing this code into XAMLPad simply displays a ", – ". This is because the goal is to bind the page fields to the properties of a player. To set up the binding, the XAML code must be edited. The following XAML code shows the profile being populated from an object. The additions made to the previous code sample are formatted in blue.

<Window x:Class="Source_Code.Profile"
   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   xmlns:AppCode="clr-namespace:Source_Code"
   Title="Player Profile" Height="300" Width="300"
   >
   <StackPanel Name="ProfileStackPanel" Orientation="Horizontal">
      <StackPanel.Resources>
         <AppCode:Player x:Key="profile" FirstName="/img/2006/12/Chad"
                         LastName="Campbell" Position="WR" />
      </StackPanel.Resources>
      <TextBlock Name="LastNameTextBlock"
                 Text="{Binding Path=LastName}" />
      <TextBlock Text=", " />
      <TextBlock Name="FirstNameTextBlock"
                 Text="{Binding Path=FirstName}" />
      <TextBlock Text=" - " />
      <TextBlock Name="PositionTextBlock"
                 Text="{Binding Path=Position}" />
      <StackPanel.DataContext>
         <Binding Source="{StaticResource profile}" />
      </StackPanel.DataContext>
      </StackPanel>
</Window>

To implement binding, the first step was defining the source to be bound to. This definition occurs within the <StackPanel.Resources /> element at the line that begins with <AppCode:Player. This line instantiates an instance of the Player class and assigns the values of the objects properties, which demonstrates the ability to define objects via markup code within WPF. (Other items can be placed within the resources section, but the preceding example implements only a data source.)

Next, the mappings between the object's properties (the Player's properties) and how to display them is implemented. This occurs in the Text attributes, which define which object (Player) property to use with the field. This is accomplished through the Binding markup extension. The Binding keyword declares the mapping through a series of comma-delimited name/value pairs.

Finally, the <StackPanel.DataContext /> element defines the data, or information scope, that the child elements of the StackPanel will consume. This could have been bypassed by appending an additional name/value pair within the Binding definition for each Text attribute.

Data-Binding Boosters

Data binding provides many ways to improve overall code quality and minimize maintenance tasks. The addition of the DependencyObject and the DependencyProperty extends data-binding benefits and adds significant power with minimal code adjustments.

Download the Code

Download the code for the example application.

MSDN Resources

About The Author

Chad Campbell (MCSD, MCTS) is a solutions developer for mid- to large-sized organizations. He is a thought leader specializing in Web-based solutions for Crowe Chizek in Indianapolis, Indiana. Reach him at cacampbell@crowechizek.com.
Share:
Home
Mobile Site | Full Site
Copyright 2017 © QuinStreet Inc. All Rights Reserved