Data binding in Windows Presentation Foundation (‘Avalon')

This article was originally published in VSJ, which is now part of Developer Fusion.
Data – it’s at the heart of nearly every application that we write today, and it’s something that we have to display to users for their delectation and amusement. In this article I will introduce you to some (a mere fraction, if truth be told) of the data binding features of Windows Presentation Foundation (WPF). On the way through, we’ll also look at how you can write types that will work well with Windows Forms and ASP.NET 2.0 data binding too.

Simple data binding

I’ve lost count of the number of classes and structures I’ve written, and I’m sure that you have, too. However, increasingly I find myself writing types whose purpose is to act as a representation of a piece of data that I need to display to the user, and which I might persist in a database. For example, I try to keep track of deadlines (that I’m missing!) using a small utility program, which I call Deadliner. In this application, a deadline is represented by a simple class:
public class Deadline {
	private string _title;
	private DateTime _dueDate;
	public string Title {
		get { return _title; }
		set { _title = value; }
	}
	public DateTime DueDate {
		get { return _dueDate; }
		set { _dueDate = value; }
	}
	// .ctors, etc.
}
Of course, what we’re trivially looking to do is to be able to bind up a Deadline object to controls that will enable us to edit its content, as depicted in Figure 1.

Figure 1
Figure 1

To display a Deadline object in the UI controls only takes a couple of lines of code, setting the Text and Value properties of the TextBox and DatePicker respectively to the public Title and DueDate properties on the object. Similarly, reading the values back into the object is also only a further two lines of code. However, this code is mundane and you shouldn’t have to write it: fortunately, and in keeping with Windows Forms and ASP.NET, in WPF you don’t have to. DataContext The (abbreviated, without all the fluffy layout code) XAML for the Window shown in Figure 1 looks something like this:

<Window ...>
	<Grid ...>
		<TextBlock>Title:</TextBlock>
		<TextBlock>Due
			date:</TextBlock>
		<TextBox ... />
		<DatePicker ... />
		<Button ... />
		<Button ... />
	</Grid>
</Window>
I’ve highlighted the TextBox and the DatePicker controls, along with the Grid and Window, because these are the elements of interest as far as our data-binding story is concerned. These four are all derived from System.Windows.FrameworkElement, which means that all of them have a DataContext property (of type System.Object). To set the target for data binding, you can set the element’s DataContext property:
public partial class
	CreateAndEditWindow {
	public CreateAndEditWindow( dl ) {
		txtTitle.DataContext = dl;
		dpDueDate.DataContext = dl;
	}
	// ... rest of Window class
}
As you can imagine, this code would get ridiculous as soon as you present any form of complex object. Therefore, you can instead choose to set the DataContext at a higher level in the tree. So, I could write:
public partial class
	CreateAndEditWindow {
	public CreateAndEditWindow(
		Deadline dl ) {
		this.DataContext = dl;
	}
	// ... rest of Window class
}
Now, when I bind the controls to the properties, the controls will walk up the hierarchy, starting with themselves, to locate the first non-null DataContext, which will become that control’s data source.

{Binding}

So how do we actually bind the control to the data? Of course, this is something that is best done in XAML (although it can be done using code). In XAML, you establish a data-binding relationship with the {Binding} syntax, as shown below:
<TextBox Text=”{Binding Path=Title}”
	... />
<DatePicker
	Value=”{Binding Path=DueDate}” />
The Path tells WPF which property on the object should be bound to the control’s property. You can omit the Path= to simplify the {Binding} instruction and just use, for example:
<TextBox Text=”{Binding Title}” ... />
There is also a longer form of binding syntax, shown here:
<DatePicker ...>
	<DatePicker.Value>
		<Binding Path=”DueDate” />
	</DatePicker.Value>
</DatePicker>

Understanding binding modes

By default, controls such as DatePicker and TextBox, which are designed to support editing by the user, will perform two-way binding. Display-only controls, such as TextBlock or Button, will perform one-way binding (from the source object to the target control). You can even have one-time only binding, which is useful for read-only data that won’t change over the course of the object’s lifetime. The binding mode is controlled using the Mode property of the Binding, as shown below:
<TextBox Text=”{Binding Path=Title,
	Mode=OneWay}” ... />
Of course, this might not make sense for a TextBox control, unless it was read-only, as using this mode will mean that any changes that the user makes will not be reflected back to the object. Changes in the object, on the other hand, will be updated to the UI control. However, whether you are performing two-way or one-way binding, there is one requirement for your type: it has to provide notifications when the object’s properties change. WPF therefore expects data-bound objects’ types to support the INotifyPropertyChanged interface. A better implementation of our Deadline type might look like this:
public class Deadline :
	INotifyPropertyChanged {
	private string _title;
	private DateTime _dueDate;
	public string Title {
		get { return _title; }
		set {
			_title = value;
			OnPropertyChanged(
		new PropertyChangedEventArgs(
				“Title) );
		}
	}
	public DateTime DueDate {
		get { return _dueDate; }
		set {
			_dueDate = value;
			OnPropertyChanged(
		new PropertyChangedEventArgs(
				“DueDate”) );
		}
	}
	public event
		PropertyChangedEventHandler
		PropertyChanged;
	protected virtual void
		OnPropertyChanged(
		PropertyChangedEventArgs e ) {
		if( PropertyChanged != null ) {
			PropertyChanged( this, e );
		}
	}
}
WPF will now automatically connect a handler to the PropertyChanged event and will update the appropriate content in any bound controls, without you having to write any event handlers.

Binding to lists of objects

Unfortunately, I never seem to have just a single deadline to meet. Consequently, I need to be able to bind a collection of DeadLine objects up to, say, a ListBox (and being WPF, of course, your ListBox can look pretty much as you’d want it to). For example, I like to colour code my deadlines like traffic lights (Red are must do NOW, Orange are think about tomorrow, Green are not worth thinking about). Therefore, my deadline ListBox looks something like Figure 2.

Figure 2
Figure 2

The (heavily trimmed) XAML for this portion of the application looks like this:

<Window ... >
	<Grid>
		<ListBox ... >
	</Grid>
</Window>
Again, the first priority is to set up the DataContext, which is done in this case for the entire Window in the Window’s constructor to
// In Window’s constructor
List<DeadLine> deadlines =
	new List<DeadLine>();
... // populate list of deadlines
this.DataContext = deadlines;
Data binding to the ListBox then consists of a single attribute:
<ListBox ItemsSource=”{Binding}” />
Notice that this time there is no Path specified for the binding, as we want to bind to the entire collection. This produces the output shown in Figure 3.

Figure 3
Figure 3

At first glance, this looks somewhat disappointing. When WPF is presented with a list of data types like this, all it can do is bind up against the output of the ToString() method on each object, which simply yields the type name unless you override it. Whilst you can override ToString(), there’s an even cooler way of presenting the data: Data templates.

Data templates

As you would expect, WPF excels at styling and customising output. For example, the following code specifies an ItemTemplate for the ListBox:
<ListBox ItemsSource=”{Binding}”
	ItemTemplate=”{StaticResource
	lbTemplate}” >
	<ListBox.Resources>
		<DataTemplate
			x:Key=”lbTemplate”>
			<Grid>
			<Border Color=”Black” ... />
			<StackPanel>
			<TextBlock Text=
			“{Binding Path=Title}” />
			<TextBlock Text=
			“{Binding Path=DueDate}” />
			</StackPanel>
			</Grid>
		</DataTemplate>
</ListBox.Resources>
This means that every ListBoxItem will be rendered using the matching template, which in this case is held as a keyed resource in the ListBox’ resource dictionary. The DataTemplate can be held as a resource at any level in the tree, including at the application level. This would make it available to other elements as necessary. The output for this list is shown in Figure 4.

Figure 4
Figure 4

Notice also that the two TextBlocks are bound using a standard {Binding} syntax, specifying the Path to the property on the specific object within the list that should be bound into the current ListBoxItem. Sadly, it still doesn’t look as (subjectively) attractive as Figure 2, so let’s fix that using converters.

IValueConverter

You can move far beyond binding strings. If you look at Figure 2, for example, you will notice that the items are colour coded according to their proximity to the current date. This can be achieved using a value converter, which is nothing more than a simple class that implements IValueConverter. Here’s the converter code that returns a brush for the item:
class DeadlineDateColorConverter :
	IValueConverter
{
	static LinearGradientBrush
		_redBrush =
		new LinearGradientBrush(
		Colors.White,
		Colors.Red, 90.0 );
	static LinearGradientBrush
		_orangeBrush =
		new LinearGradientBrush(
		Colors.White,
		Colors.Orange, 90.0 );
	static LinearGradientBrush
		_greenBrush =
		new LinearGradientBrush(
		Colors.LightGreen,
		Colors.Green, 90.0 );
	public object Convert(
		object value, Type targetType,
		object parameter, CultureInfo
		culture ) {
		Brush retVal;
		DateTime dt = (DateTime)value;
		TimeSpan ts = dt.Subtract(
			DateTime.Now );
		if( ts.Days <= 10 )	{
			retVal = _redBrush;
		} else if( ts.Days <= 30 ) {
			retVal = _orangeBrush;
		} else {
			retVal = _greenBrush;
		}
		return retVal;
	}
	public object ConvertBack(
		object value, Type targetType,
		object parameter,
		CultureInfo culture ) {
		throw new
			InvalidOperationException(
			“Not expected”);
	}
	static DeadlineDateColorConverter()
		{
		_redBrush.Freeze();
		_greenBrush.Freeze();
		_greenBrush.Freeze();
	}
}
The most important part of this class is the Convert() method, whose job is to take the source object’s property data (in this case a boxed DateTime) and convert it to the appropriate output type, which in this case is a LinearGradientBrush containing a red, orange or green gradient fill.

Note: You might be wondering what the Freeze() method does on the brushes. Well, it informs WPF that the object is not going to change, which helps WPF optimise its rendering code because it doesn’t need to worry about changes to the object.

To tell WPF to use our converter during the binding operation requires a few lines of XAML. To start with, we will be using our converter class as a keyed resource, which involves bringing our converter class’ namespace is in scope. To do this we add a Mapping directive to the source file, connect the XML namespace to the CLR namespace and then add the resource. As my namespace for my C# code is called Deadliner, the mapping directive looks like this:

<?Mapping XmlNamespace=”dl”
	ClrNamespace=”Deadliner” ?>
I decided to add the converter as a resource at the Window level, so the XAML for the window now reads:
<Window ...
	xmlns:dl=”dl”
	... >
	<Window.Resources>
		<dl:DeadlineDateColorConverter
x:Key=”DeadlineDateColorConverter />
	</Window.Resources>
	...
</Window>
Finally, we use the converter within the DataTemplate to colour the background using a Rectangle like so:
...
<Border ... >
	<Rectangle ... Fill=”{Binding
		Path=DueDate, Converter=
			{StaticResource
		DeadlineDateColorConverter}}”/>
</Border>
...
There are a number of standard converters available, which deal with the intrinsic data types. However, as you can see, you can easily match any attribute on the UI element to any property on the object using converters, which makes them a formidable tool in the data-binding arsenal.

Adding and removing items from the list

Implementing INotifyPropertyChanged enables WPF to track changes to an object: but what about when changes, such as adding or removing an item, occur on a bound collection? Fortunately, there is an interface, INotifyCollectionChanged, which WPF can use to track changes and then update the UI to match. However, there’s a catch: common collections such as List<T> don’t support INotifyCollectionChanged.

Before you get too disappointed and start heading out to implement your own set of generic classes, you’ll be pleased to know that the WPF team have provided a collection that does implement INotifyCollectionChanged. It’s called ObservableCollection<T> and it can be found in the System.Collections.ObjectModel namespace. I tend to create a derived, non-generic collection, which derives from ObservableCollection<T>. This is because WPF has a declarative binding model (which I’m not going to talk about in this article), where everything is done in XAML, and having <> in a class name is always exciting in an XML-based syntax. In the case of Deadliner, I have:

public class Deadlines :
	ObservableCollection<T>
{}
As you can well imagine, a Deadlines object is populated and then assigned into the DataContext for the Window.

Filtering and Sorting

Once you have your collection in place, you might want to control the items that are actually displayed and the order that they are shown. You can do this by applying a filter and a sort. There are two different ways to apply a Filter, and the way that I’m going to demonstrate here is dependent on the type of the data source, but it works well for ObservableCollection<T> and for XML data sources. The filter is implemented using a delegate, so we can quickly crank out the following code:
private void SetFilter( int dayLimit )
	{
	ICollectionView cv =
CollectionViewSource.GetDefaultView(
		this.DataContext );
	cv.Filter = delegate(object item) {
		DateTime due = ((Deadline)
			item).DueDate;
		TimeSpan ts = due.Subtract(
			DateTime.Now );
		return (ts.Days <= dayLimit );
	};
}
You can probably infer from the code that we are looking at the default view of our data, and then we use an (in this example, anonymous) delegate for the Filter property on the view. For each item, the filter will be checked and, as long as the filter delegate method returns true, the object will be displayed. The output is now limited to the urgent deadlines, as shown in Figure 5.

Figure 5
Figure 5

Of course, the eagle-eyed amongst you will spot the immediate problem: the tasks are in the wrong order and I really need them sorted by ascending date to make sure that the most pressing deadline appears first.

Fortunately, the ICollectionView interface has a Sort property, which refers to a SortDescriptionCollection that can be used to set the sort sequence by adding SortDescription objects. The code below will sort the list of Deadline objects by DueDate.

private void SortByDueDate() {
	ICollectionView cv =
CollectionViewSource.GetDefaultView(
		this.DataContext );
	SortDescription sd = new
		SortDescription( “DueDate”,
		ListSortDirection.Ascending );
	cv.Sort.Add( sd );
}

Master/detail binding

Having a list of deadlines is great, but I also need to keep track of the tasks that have to be done before the deadline can be considered completed. As this is only a quick reminder tool, I don’t need too much detail for each task, so it looks like this:
public class Task :
	INotifyPropertyChanged {
	private string _title;
	public string Title	{
		get { return _title; }
		set {
			_title = value;
			OnPropertyChanged(
		new PropertyChangedEventArgs (
				“Title” ) );
			}
		}
		private bool _completed;
		public bool Completed {
			get { return _completed; }
			set {
				_completed = value;
				OnPropertyChanged(
		new ProperyChangedEventArgs (
					“Completed” ) );
			}
		}
		public Task( string title ) {
			Title = title;
		}
		public event
			PropertyChangedEventHandler
			PropertyChanged;
		protected virtual void
			OnPropertyChanged(
		PropertyChangedEventArgs e ) {
		if( PropertyChanged != null ) {
			PropertyChanged( this, e );
			}
		}
	}
	public class Tasks :
		ObservableCollection<Task>
	{}
As you can see, I’ve followed the same approach as for the Deadline class, making sure that it supports INotifyPropertyChanged so that we can get one- and two-way data-binding support. The Deadline class is then modified to add support for the task list as follows:
public class Deadline {
	// original parts omitted
	// for brevity
	private Tasks _tasks = new Tasks();
	public Deadline(
		DateTime due, string title ) {
		DueDate = due;
		Title = title;
		_tasks = new Tasks();
		_tasks.CollectionChanged +=
			delegate(object sender,
NotifyCollectionChangedEventArgs e ) {
			if( e.Action ==
NotifyCollectionChangedAction.Add ) {
				foreach( Task t in
					e.ChangedItems ) {
		t.PropertyChanged += delegate(
						object s,
		PropertyChangedEventArgs ep ) {
if( ep.PropertyName == “Completed” ) {
			OnPropertyChanged(
		new PropertyChangedEventArgs(
				“TasksOutstanding” ) );
						}
					};
				}
			}
			OnPropertyChanged(
		new PropertyChangedEventArgs(
				“TasksOutstanding” ) );
		};
	}
	public int TasksOutstanding {
		get {
			int retVal = 0;
		foreach( Task t in _tasks ) {
				if( !t.Completed ) {
					retVal++;
				}
			}
			return retVl;
		}
	}
	public int TaskCount {
			get { return _tasks.Count; }
	}
	public Tasks Tasks { get {
		return _tasks; } }
The Deadline class now exposes a collection of Task objects that can be bound to elements in the UI. It also provides a new property, TasksOutstanding, which tells me how many tasks have yet to be completed. I’ve also used the CollectionChanged event handler (for Tasks) to add on a PropertyChanged event handler for any new Task objects so that I can change the state of the UI whenever the user marks a task as being completed. Note that I don’t necessarily recommend the use of nested anonymous delegates, but it does make for brief code. The UI that I’m looking to produce from this code is shown in Figure 6.

Figure 6
Figure 6

Notice that the Deadline now displays the number of outstanding tasks, with the ListBox on the right hand side displaying the actual tasks. Again, a DataTemplate is used for each of the ListBoxes, with the main Deadline list using this template:

<DataTemplate x:Key=”lbTemplate”>
	<Grid Margin=”2,3,8,3”>
		<Border BorderBrush=”White”
			BorderThickness=”2”
				CornerRadius=”8” >
			<Rectangle RadiusX=”6”
				RadiusY=”6”
			Fill=”{Binding Path=DueDate,
				Converter={StaticResource
		DeadlineDateColorConverter}}”
		HorizontalAlignment=”Stretch”
		VerticalAlignment=”Stretch” />
		</Border>
		<StackPanel Margin=”5,5” >
			<TextBlock Margin=”1,1”
		Text=”{Binding Path=Title}” />
<StackPanel Orientation=”Horizontal”>
				<TextBlock Margin=”1,1”
			Text=”{Binding Path=DueDate,
				Converter={StaticResource
				ShortDateConverter}}” />
			<TextBlock Margin=”5,0,0,0”
				Text=”(“ />
				<TextBlock Margin=”1,1”
					Text=”{Binding
			Path=TasksOutstanding}” />
				<TextBlock Text=”)” />
</StackPanel> </StackPanel> </Grid> </DataTemplate> The highlighted code shows the extra mark-up for the outstanding task count. Since I’ve implemented INotifyPropertyChanged for Task, and I handle the change in the corresponding Deadline object, whenever I change the status of the Completed property on a Task the UI automatically updates to show me one less task to complete.

The ListBox of the tasks uses the following DataTemplate:

<DataTemplate
	x:Key=”taskItemTemplate”>
	<DockPanel Margin=”2,2”
		LastChildFill=”True”>
		<CheckBox IsChecked=”{Binding
			Path=Completed}”
			VerticalAlignment=”Center”
			DockPanel.Dock=”Left”/>
		<TextBlock Text=”{Binding
				Path=Title}”
				Margin=”4,0,0,0” />
	</DockPanel>
</DataTemplate>
The interesting thing to note here is the {Binding Path}. In this case, Completed and Title are properties on the Task, not Deadline, type. So how does WPF know to pick them from the current Task object that is being highlighted in the list of Deadlines? The key to this is {Binding} code for the ListBox itself, which looks like this:
<ListBox x:Name=”lstTasks”
ItemsSource=”{Binding Path=Tasks}” >
At this point, you must remember that the list of Deadlines is bound into the DataContext of the Grid element that contains both ListBoxes. You can therefore think of the {Binding Path=Completed}, for example, as actually being:
{Binding Path=Deadlines.CurrentItem.
	Tasks[indexInList].Completed}

The current position

This throws up interesting questions: how do we know what the current item is, and how is it related to the current selection in the ListBox?

When binding to a collection, WPF maintains a current item, which can be accessed through the ICollectionView.CurrentItem property. There’s also the notion of the CurrentPosition, which can be adjusted with via a number of MoveCurrentToxxxx methods. One thing to watch out for is that you can move off the end of the collection, so you might find yourself writing code like this:

public void MoveToNextItem() {
	ICollectionView icv =
CollectionViewSource.GetDefaultView(
		xxx.DataContext );
	icv.MoveCurrentToNext();
	if( icv.IsCurrentAfterLast ) {
		icv.MoveCurrentToLast();
	}
}
Don’t panic. The various MoveCurrentToxxx methods aren’t something that you have to work with everyday. A ListBox, for example, can be made to synchronise its selected item and the current position automatically. To do this in XAML you use the IsSynchronizedWithCurrentItem property, as shown below:
<!- Listbox containing the Deadlines
	collection ->
<ListBox ItemsSource={Binding}
	IsSynchronizedWithCurrentItem=
	”true” />

Data providers

So far, I have been directly binding to data that is being instantiated somewhere in code. Of course, part of the challenge of data binding comes from loading the objects in the first place. In many cases, we won’t actually be using objects, but will be reading content from XML, Web Services or relational databases. Given that I’m busy, but not too busy, I can typically store my collection of deadlines in an XML file that looks something like this:
<?xml version=”1.0”
	encoding=”utf-8” ?>
<Deadlines>
	<Deadline
	Title=”VSJ Article on Databinding”
		DueDate=”25/10/2005” >
		<Tasks>
	<Task Title=”Plan article content”
				Completed=”true” />
	<Task Title=”Write demonstration
		programs”
				Completed=”true” />
			<Task Title=”Write article”
				Completed=”false” />
			...
		</Tasks>
	</Deadline>
	...
</Deadlines>
So how do we hook up a blob of XML using data binding? Mercifully, it can be done with just a couple of lines of XAML:
<Grid DataContext=”{StaticResource
	xmlDeadlines}”>
	<Grid.Resources>
<XmlDataProvider x:Key=”xmlDeadlines”
		Source=”Deadlines.xml”
		XPath=”/Deadlines/Deadline” />
		...
	</Grid.Resources>
	...
</Grid>
This hooks the source up to the Deadlines.xml file, which is assumed to be in the same folder as the application in this scenario. The DataContext for the Grid (and everything in it, unless the override it) is also set declaratively. Perhaps the most interesting part of this is that an XPath path is specified for type that should be bound in. This has further ramifications, because you need to use XPath queries for all of the {Binding} statements that follow. Therefore, when we look at the DataTemplate for the ListBoxItems, we see:
<DataTemplate x:Key=”lbTemplate”>
	...
	<StackPanel Margin=”5,5” >
		<TextBlock Margin=”1,1”
	Text=”{Binding XPath=@Title}” />
		<TextBlock Margin=”1,1”
		Text=”{Binding XPath=@DueDate,
			Converter={StaticResource
			XmlShortDateConverter}}” />
	</StackPanel>
	...
</DataTemplate>
You will see that Title and DueDate, which are both attributes in the XML file, are accessed using XPath’s @ notation. You might also have noticed that I’m using a different converter for the DueDate. This is because I’m no longer using Deadline objects, but I’m now using XmlElements. These are less strongly typed: DueDate is now an attribute, not a DateTime object.

Data providers in WPF have support for deferred and asynchronous retrieval, and you can write your own provides by deriving from the System.Windows.Data.DataSourceProvider class.

Binding to other UI elements

There are going to be times when you will want to bind properties on one element to those of another. For example, you might want to set the Enabled property of a Button depending on whether a TextBox contains some content:
...
<TextBox x:Name=”txtPassword” />
<Button IsEnabled=”{Binding
	ElementName=txtPassword,
	Path=Text, Mode=OneWay,
	Converter={StaticResource
	TextLengthToBoolConverter}}”>
	Login
</Button>
...
In this example, a custom converter is used to convert the string to Boolean value based.

Conclusion

Data binding is very much a first-class citizen in the Windows Presentation Foundation.

I’ve barely scratched the surface of the subject with this introductory article, but I hope that you can see that you can write great, interactive, data-driven user interfaces using WPF.


Dave Wheeler is a Microsoft Certified Trainer, holds the MCSD.NET certification and works as a Principal Technologist at QA. You can read his blog at blogs.effectivexaml.net/DaveWheeler. Dave will be presenting a number of sessions on WPF at DevWeek 2006.

You might also like...

Comments

About the author

Dave Wheeler United Kingdom

Dave Wheeler is a freelance instructor and consultant who specialises in .NET application development. He’s a moderator on Microsoft’s ASP.NET and Silverlight forums and is a regular speaker at ...

Interested in writing for us? Find out more.

Contribute

Why not write for us? Or you could submit an event or a user group in your area. Alternatively just tell us what you think!

Our tools

We've got automatic conversion tools to convert C# to VB.NET, VB.NET to C#. Also you can compress javascript and compress css and generate sql connection strings.

“The question of whether computers can think is just like the question of whether submarines can swim.” - Edsger W. Dijkstra