Data and Silverlight 2: Data Binding

Silverlight 2 is far more versatile than Silverlight 1. It can handle data-sources with some subtlety. John Papa tackles the whole subject of data-binding with Silverlight. This article is a partial excerpt from John Papa's upcoming book Data Access with Silverlight 2 by O'Reilly, due to be released in December 2008.

Data and Silverlight 2: Dependency Properties and Binding Syntax

Unlike Silverlight 1, Silverlight 2 has controls, .NET CLR support and data binding features.  This article is the first of a series that describes the basic elements of data binding with Silverlight 2.

Data binding

While binding can be established using a manual push and pull process, the data binding capabilities of XAML and Silverlight offer more power and flexibility with less runtime code. This provides a more robust data bound user-interface with fewer failure points than with manual binding.

The process of Automated Data-Binding in Silverlight links a UI FrameworkElement to a data source entity and back. The data source entity contains the data that will flow to the FrameworkElement control for presentation. The data can also flow from the control in Silverlight back to the entity. For example, an entity may be bound to a series of controls, each of which is linked to a specific property on the entity, as shown in Figure 1.

The entity is set to the DataContext for a control. This then allows that control, or any child control of that control, to be bound directly to the entity. There are many important players in this process that will be introduced in this article, including the DataContext, binding modes, and dependency properties on FrameworkElement controls. Each of these plays a critical role in customizing how the data binding process operates in a Silverlight application.

513-image001.png

Figure 1. Data binding in Silverlight 2

There are some basic rules to follow when you are setting up data binding in Silverlight. The first rule is that the target element of a data binding operation must be a FrameworkElement. The second rule says that the target property must be a Dependency Property.

Rule #1: FrameworkElement

The target of data binding must be a FrameworkElement. This many sound limiting but it is quite the opposite. The FrameworkElement has many subclasses that inherit from it. Figure 2 shows several controls that inherit from the FrameworkElement. The FrameworkElement extends the UIElement class and adds capabilities that allow it to control layout and support data binding.

Any control that derives from FrameworkElement can be used for layout on a page or user control, and can be involved in data binding as a target. There are other classes that derive from some of the subclasses shown in Figure 2, such as System.Windows.Controls.Textbox, too.

In data binding, both a data source and at least one target are required. The target can be a control or set of controls on a page (or within a user control). Basically, the data can travel in either direction between the source and the target. The sources of data are generally instances of objects such as a domain entity. The properties of the data source are referred to in the targets, so that each target control knows which property of the entity it should be bound to.

513-Leavethisalonetoo.jpg

Figure 2. FrameworkElement Class Hierarchy

Rule #2: Dependency Properties

As mentioned previously, the second rule of data binding in Silverlight is that the target must be a Dependency Property. This might initially seem to be a restriction, especially since one of the first controls people think about when they think of data binding is the TextBox’s Text property. However if you take a look at the source code (using a tool like Lutz Roeder’s .NET Reflector) for the Text property of a TextBox you will see that it too is a Dependency Property. In fact most properties that you can think of are Dependency Properties, which is great, since that means you can use data binding with so many properties.

Dependency Properties are data-bound properties whose value is determined at runtime. The purpose of dependency properties is to provide a way to determine the value of a property based on inputs including, but not limited to, user preferences, resources, styles, or data binding.  An example of a Dependency Property can be seen in the XAML code snippet below by looking at the Fill property.

The Rectangle control’s Fill property is a Dependency Property that is set to a specific color, in this case. The Fill property’s value could be determined using a resource or by data binding to an object. This would allow the color of the rectangle to be determined at runtime.

Dependency Properties are not declared as a standard .NET CLR type, but rather they are declared with a backing property of type Dependency Property. The code in Example 1 shows the public facing property Fill and its type Brush However you’ll see that its backing property is not Brush but rather the type Dependency Property. You can always identify a Dependency Property by looking at its backing property’s name. If the backing property name has the Property suffix then it is generally the backing property for a Dependency Property.

Example 1. DependencyProperty

C# code

VB Code

Table 1 shows a quick reference of these terms applied to the code in Example 1

Term

Description

Explanation

Dependency Property

The property named Fill

A property that is backed by a field of type Dependency Property

DependencyProperty

The type of FillProperty

A type that defines the backing field

Dependency Property Identifier

The instance of the backing property,FillProperty . This is referred to in the CLR Wrapper code with the GetValue and SetValue methods.

An instance of the Dependency Property

CLR Wrapper

The setter and getter accessor code for the Fill property.

The getter and setter for the property

 A dependency property can also get its value through a data-binding operation. Instead of setting the value to a specific color or a Brush, the value can be set through data-binding. When using data-binding, the property’s value is determined at runtime from the binding to the data source.

The following XAML example sets the Fill for a Rectangle using data-binding. The binding uses an inherited data context and an instance of an object data source (referred to as MyShape). The binding syntax and the DataContext will be explored later in this article.

Besides basic data binding, styles and templates are a huge beneficiary of using dependency properties. Controls that use styles are indicated through a StaticResource (defined in app.xaml or defined locally). The style resources are often set to a Dependency Property to achieve a more elegant appearance.

Dependency Property values are determined using an order of precedence. For example a style resource may set the Background Dependency Property to White for a canvas control. However the Background color can be overridden in the control itself by setting the Background property to Blue. The order of precedence exists in order to ensure that the values are set in a consistent and predictable manner. The previous example of the Rectangle control shows that the locally-set property value has a higher precedence than a resource.

When creating a binding, a Dependency Property of a FrameworkElement must be assigned to the binding. This is the target of the binding operation. The source of the binding can be assigned through the DataContext property of the UI element or any UI element that is a container for the bound UI element.

Silverlight Binding XAML Markup Extensions

One of the main pieces of functionality offered by the Dependency Property is its ability to be data bound. In XAML, the data binding works through a specific markup extension syntax. Alternatively, the binding can be established through .NET code. A set of XAML attributes exist in order to support the data binding features. A basic example of the usage of these extensions is shown in the pseudo-code examples below.

The element must be a FrameworkElement (thus the name someFrameworkElement). The property would be replaced with the name of the property that will be the target of the binding. For example the element might be a TextBox and the property might be Text. To bind the value of the property to a source the binding markup extensions can be used.

The Binding attribute indicates that the value for the Dependency Property will be derived from a data binding operation. The binding gets its source from the DataContext for the element or the DataContext that is inherited from the closest parent element. To bind an element to an object that is the DataContext (and not to a property of the object), all that is needed is the Binding attribute (see the first line of XAML from the previous example). For example, this is usually the case when binding an object that is a list to a ListBox.

The second usage of the binding markup syntax is to specify a pathvalue. This can be the name of a property that exists on the bound object. For example, to bind a TextBox’s Text property to the CompanyName property of an object in the inherited DataContext the following code could be used:

Binding Extension Properties

Additionally, there are a handful of other binding properties (referred to in the previous example as oneOrMoreBindingProperties) that can be set with the XAML binding extensions in Silverlight. These properties are:

  • Converter
  • ConverterCulture
  • ConverterParameter
  • Mode
  • Source
  • Path
  • NotifyOnValidationError
  • ValidatesOnExceptions

The Mode indicates the binding mode that specifies how the binding will operate. Valid values for the Mode property are OneTime, OneWay and TwoWay. An object reference can be set to the Source property. If the Source property is set the object reference will override the DataContext as the data source for this binding. All of these properties are optional. The default value for the Mode is OneWay while if the Source property is omitted the data source will defer to the DataContext.

Keep in mind that a Dependency Property follows an order of precedence to determine its value. If a Dependency Property is bound and in code the property is set to a value explicitly, the binding is removed. For example the tbCompany TextBox in the previous example is bound to the CompanyName property of the DataContext. If the Text property of tbCompany is set to Foo in code, then the binding is removed.

DataContext

The DataContext refers to a source of data that can be bound to a target. The DataContext often is set to an instance of an entity. Once set, the DataContext can be bound to any controls that have access to it. It can be used to bind all controls within a container control to a single data source. This is useful when there are several controls that all use the same binding source. It could become repetitive to indicate the binding source for every control. Instead, the DataContext can be set for the container of the controls.

Each FrameworkElement has a DataContext. This includes the instances of the UserControl class that the examples in this article have demonstrated, since the UserControl class inherits from the Control class which in turn inherits from the FrameworkElement  class. This means that, on a single UserControl, there could be objects assigned to dozens of DataContext properties of various FrameworkElement  controls. For example the UserControl, a layout control such as a Grid, and a series of interactive controls such as the TextBox, CheckBox and ListBox controls might all have their DataContext property set.

To use the DataContext, the XAML must also be modified using the binding markup extension syntax. The newly modified XAML for the UserControl is shown in the code example below. This code is only the portion of the entire XAML file that shows only the elements where binding takes place.

This XAML shows that the Text property of each TextBox is bound to a property of the data source. The data source is not listed anywhere in this XAML code. Therefore it is inferred that the Binding will use the DataContext that is closest in the inheritance hierarchy to the Target. If the TextBox itself has its DataContext property set, it will use the object from its own DataContext.

Example 2. DataContext Binding

C#

VB Code

The code in Example 2 shows the event handler that will execute when the UserControl is loaded. First an instance of the Person class is created and initialized. Then the DataContext property (also a Dependency Property) of the UserControl is set to the person instance. This gives each TextBox’s Binding a valid DataContext to use as the data source. Figure 3 shows the result of the binding. The DataContext is set for a container control (the UserControl itself).

513-Leavethisalonethree.jpg

Figure 3. DataContext Binding

Summary

Silverlight 2 offers a variety of data binding features that all stem from some basic concepts as discussed in this article. All instances of the FrameworkElement class support data binding as a target while all properties of FrameworkElements that are dependency properties can be a target property of a data binding operation. The DataContext is a very powerful way to bind a source object to one or more elements are multiple levels in XAML. These are the fundamental tools to data binding with Silverlight 2.