RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX


Flexible and Powerful Data Binding with WPF : Page 3

Microsoft has been building data binding frameworks for years, and each promises to solve our data binding woes forever. But we're still waiting for the perfect one. Could WPF data binding be the one we've been waiting for?

Change Notification
Nearly any .NET property can serve as a data source. In the previous example the data source was the Value property on a Slider element, which returns a Double value. The framework loads the data into the data target on initialization. If you establish a two-way binding (details later in this article) the data will also flow back to the data source. The WPF dependency system can keep the data synchronized when the source property changes; however, this is not automatic. To accomplish the synchronization, the source property must implement some form of change notification—basically, your type must tell the framework that the underlying data has changed. There are a several ways to accomplish this in your data source:

  • INotifyPropertyChanged: Implement this .NET 2.0 interface and create the PropertyChanged event. In your property setters, raise the PropertyChanged event whenever the value changes. This is the preferred technique in WPF.
  • DependencyProperty: Derive from DependencyObject and create a DependencyProperty. All change notification is handled by the WPF dependency property system. A side effect of this approach is that you create a dependency on the WPF assemblies in your business class assembly.
  • xxxPropertyChanged events: In .NET 1.x you can create an event with the same name as your property (e.g. WidthChanged) and raise the event when the property (Width) changes. Microsoft made sure that this scenario works in WPF because it makes it possible to bind to older .NET types. While it is usable, you'll find that INotifyPropertyChanged is easier to work with.
Listing 1 shows a sample business object that implements INotifyPropertyChanged, while Listing 2 shows an example of the DependencyProperty approach.

Data Context
Naturally, WPF is not limited to employing UI elements as data sources; it also offers the ability to bind to non-UI data. Every binding requires a data source object and a path to the source property. A data context lets the framework look for a source object further up the logical tree. All FrameworkElements and FrameworkContentElements have a DataContext property. Here's an example:

   <TextBlock   Text='{Binding Path=Salary}' />
What's going on here? The Path property points to the Salary property but where is the XAML that specifies the data source? To answer that question, look at the following code.

   // C#:
   // in the Loaded event procedure
   var emp = new Employee();
     emp.FirstName = "Johnny";
     emp.LastName = "Appleseed";
     emp.Salary = 15000M;
   // sets the Datacontext for the Page
   this.DataContext = emp;
   ' Visual Basic:
   ' in the Loaded event procedure
   Dim emp = New Employee()
     emp.FirstName = "Johnny"
     emp.LastName = "Appleseed"
     emp.Salary = 15000D
   ' sets the Datacontext for the Page
   Me.DataContext = emp
The preceding code sets the data context explicitly. The last line in each snippet sets the data context for the entire page. When the binding object can't find a data context on the TextBlock, it walks the logical tree looking for a data context on a parent element. If none is found, the default error handling occurs. Because the page is a parent element, the binding object will use its data context in this case.

You can also apply different data contexts to elements on a page, as the next snippet shows:

   // C#:
   // setting different data contexts
   var emp1 = new Employee();
   emp1.LastName = "Appleseed";
   stackPanel1.DataContext = emp1;
   emp2 = new Employee();
   emp2.LastName = "Washington";
   dockPanel1.DataContext = emp2;
   ' Visual Basic:
   ' setting different data contexts
   Dim emp1 = New Employee()
   emp1.LastName = "Appleseed"
   stackPanel1.DataContext = emp1
   Dim emp2 = New Employee()
   emp2.LastName = "Washington"
   dockPanel1.DataContext = emp2
The preceding code sets different data contexts for the StackPanel and DockPanel.

The Binding class constructor takes a Path string, meaning you can leave off the Path property entirely and use the shorter syntax shown here:

   <TextBlock   Text='{Binding Path=Salary}' />
   <!-This binding works without the
   explicit Path property-->
   <TextBlock   Text='{Binding Salary}' />
Binding Extension
The Binding class is the main actor in the data binding story. It has a simple and easy to understand API. Here are some of the common binding properties:

  • ElementName: The data source is a different element. You must specify the source element's name specified, usually with the x:Name attribute.
  • Source: Provide a reference to a valid object source. A binding configured with the Source property takes precedence over any applied data context.
  • RelativeSource: The source is a property on a related object.
  • Path: Provide navigation instructions for finding the data source property. The simplest path is merely the name of a property, as in the example below:
  •    <!-- Path to sub properties-->
       <TextBlock xx='{Binding Path=UserName.Length}' />
       <!-- Path to attached property -->
       <TextBlock xx='{Binding Path=(Canvas.Top)}' />
       <!-- Path to Indexer property-->
       <TextBlock xx='{Binding Path='{Brushes[2]}' />
  • XPath: Provide XPath navigation instructions for finding the XML source node.

Close Icon
Thanks for your registration, follow us on our social networks to keep up-to-date