Introduction
This article explains the absolute basics of WPF data binding. It shows four different ways to perform the same simple task. Each iteration moves closer to the most compact, XAML-only implementation possible. This article is for people with no experience in WPF data binding.
Background
Programming in WPF involves a lot of data binding. WPF user interfaces typically use much more data binding than most Windows Forms or ASP.NET user interfaces. Most, if not all, data movement in the user interface is accomplished with data binding. This article should help WPF newbies to start thinking in terms of WPF data binding, by showing how to translate a code-only solution into a compact XAML-only solution.
This article does not discuss the binding API much. It only discusses what is relevant to the simple example. If you would like to read more about the technical details of WPF data binding, you can read my article about it here.
The Demo App
Throughout this article, we will examine several ways to implement the same simple functionality. Our goal is to create a WPF program that allows us to edit a person’s first and last name. The application should also display that person’s name, formatted as <LastName>, <FirstName>. The formatted name should immediately update whenever the first or last name changes.
The user interface should look something like this:
Version 1 – Manually Moving Data
First, we will not use data binding to implement this. Let’s create a simple class to hold the person’s name:
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string FullName
{
get
{
return String.Format("{0}, {1}",
this.LastName, this.FirstName);
}
}
}
Next, we declare a simple user interface in XAML. These controls will display the three properties of our Person
class. They exist in our application’s main Window
:
<StackPanel>
<TextBox
x:Name="firstNameTextBox"
Width="200"
Margin="0,4"
/>
<TextBox
x:Name="lastNameTextBox"
Width="200"
Margin="0,4"
/>
<TextBlock
x:Name="fullNameTextBlock"
Background="LightBlue"
Margin="0,4"
/>
</StackPanel>
Finally, we can write some code in the Window
’s code-behind file to manually move the data around as necessary:
Person _person;
private void ManuallyMoveData()
{
_person = new Person
{
FirstName = "Josh",
LastName = "Smith"
};
this.firstNameTextBox.Text = _person.FirstName;
this.lastNameTextBox.Text = _person.LastName;
this.fullNameTextBlock.Text = _person.FullName;
this.firstNameTextBox.TextChanged += firstNameTextBox_TextChanged;
this.lastNameTextBox.TextChanged += lastNameTextBox_TextChanged;
}
void lastNameTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
_person.LastName = this.lastNameTextBox.Text;
this.fullNameTextBlock.Text = _person.FullName;
}
void firstNameTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
_person.FirstName = this.firstNameTextBox.Text;
this.fullNameTextBlock.Text = _person.FullName;
}
Bugs are born in this type of code, like a swamp. This implementation requires the UI code to keep track of what controls need to be updated when certain property values change. This forces us to duplicate knowledge of the problem domain in our UI code, which is never a good thing. If we were dealing with a more complex problem domain, this type of code can get very ugly very fast. There must be a better way…
Version 2 – Binding in Code
Using the exact same XAML in our Window
, let’s rewrite the code-behind so that the controls are data bound to the Person
object. Instead of having the Window
’s constructor call the ManuallyMoveData
method, as seen before, now it will call this method instead:
private void BindInCode()
{
var person = new Person
{
FirstName = "Josh",
LastName = "Smith"
};
Binding b = new Binding();
b.Source = person;
b.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
b.Path = new PropertyPath("FirstName");
this.firstNameTextBox.SetBinding(TextBox.TextProperty, b);
b = new Binding();
b.Source = person;
b.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
b.Path = new PropertyPath("LastName");
this.lastNameTextBox.SetBinding(TextBox.TextProperty, b);
b = new Binding();
b.Source = person;
b.Path = new PropertyPath("FullName");
this.fullNameTextBlock.SetBinding(TextBlock.TextProperty, b);
}
In this version, we are no longer directly assigning values to the Text
property of a TextBox
or TextBlock
. Now we are binding those properties on the controls to a property on the Person
object. The Binding
class is part of WPF; in fact, it is a core piece of all WPF data binding. Setting a Binding
object’s Source
property indicates the data source of the binding (i.e., where the data comes from). Setting the Path
property indicates how to get the bound value from the data source. Setting the UpdateSourceTrigger
property to ‘PropertyChanged
’ tells the binding to update as you type, instead of waiting for the TextBox
to lose focus before updating the data source.
This seems all well and good, but there is a problem. If you run the program now, the formatted full name will not update when you edit the first or last name. In the previous version, the formatted full name updated because we hooked each TextBox
’s TextChanged
event and manually pushed the new FullName
value into the TextBlock
. But now, all of those controls are data bound, so we cannot do that. What’s the deal?
The WPF data binding system is not magical. It has no way to know that our Person
object’s FullName
property changes when the FirstName
or LastName
properties are set. We must let the binding system know that FullName
has changed. We can do that by implementing the INotifyPropertyChanged
interface on the Person
class, as seen below:
public class Person : INotifyPropertyChanged
{
string _firstName;
string _lastName;
public string FirstName
{
get { return _firstName; }
set
{
_firstName = value;
this.OnPropertyChanged("FirstName");
this.OnPropertyChanged("FullName");
}
}
public string LastName
{
get { return _lastName; }
set
{
_lastName = value;
this.OnPropertyChanged("LastName");
this.OnPropertyChanged("FullName");
}
}
public string FullName
{
get
{
return String.Format("{0}, {1}",
this.LastName, this.FirstName);
}
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
void OnPropertyChanged(string propName)
{
if (this.PropertyChanged != null)
this.PropertyChanged(
this, new PropertyChangedEventArgs(propName));
}
#endregion
}
Notice that the new implementation of Person
does not use automatic properties. Since we need to raise the PropertyChanged
event when FirstName
or LastName
is set to a new value, we must use a normal property and field instead.
If we run the app now, the formatted full name text updates as we edit the first or last name. This shows that the binding system is listening to the Person
object’s new PropertyChanged
event. At this point, we have gotten rid of that ugly, bug-prone code in the previous version. Our code-behind has no logic in it that determines when to update which fields.
We still have quite a bit of code. It would be better if we could declare the relationships between controls and data in XAML. That would neatly separate the UI layout and configuration away from the application logic. This is especially appealing if you want to use a design tool, such as Microsoft Expression Blend, to create your user interfaces.
Version 3 – Binding in XAML (Verbose)
Now, let’s comment out the second version and see how to move all of this binding code into XAML. In the code-behind, we will have the Window
’s constructor call this method:
private void BindInXaml()
{
base.DataContext = new Person
{
FirstName = "Josh",
LastName = "Smith"
};
}
The rest of the work is done in XAML. Here is the content of the Window
:
<StackPanel>
<TextBox
x:Name="firstNameTextBox"
Width="200"
Margin="0,4"
>
<TextBox.Text>
<Binding
Path="FirstName"
UpdateSourceTrigger="PropertyChanged"
/>
</TextBox.Text>
</TextBox>
<TextBox
x:Name="lastNameTextBox"
Width="200"
Margin="0,4"
>
<TextBox.Text>
<Binding
Path="LastName"
UpdateSourceTrigger="PropertyChanged"
/>
</TextBox.Text>
</TextBox>
<TextBlock
x:Name="fullNameTextBlock"
Background="LightBlue"
Margin="0,4"
>
<TextBlock.Text>
<Binding Path="FullName" />
</TextBlock.Text>
</TextBlock>
</StackPanel>
That XAML uses the property-element syntax to establish bindings for each control’s Text
property. It looks like we are setting the Text
property to a Binding
object, but we’re not. Under the covers, the WPF XAML parser interprets that as a way to establish a binding for the Text
property. The configuration of each Binding
object is identical to the previous version, which was all in code.
Running the application at this point shows that the XAML-based bindings work identically to the code-based bindings seen before. Both examples are creating instances of the same class and setting the same properties to the same values. However, this seems like a lot of XAML, especially if you are typing it by hand. It would be nice if there were a less verbose way to create the same bindings…
Version 4 – Binding in XAML
Using the same method in the code-behind as the previous example, and the same Person
class, we can drastically reduce the amount of XAML it takes to achieve the same goal. The key here is the fact that the Binding
class is actually a markup extension. Markup extensions are like a XAML parlor trick, allowing us to create and configure an object in a very compact way. We can use them to create an object within the value of an XML attribute. The XAML of the final version of this program is shown below:
<StackPanel>
<TextBox
x:Name="firstNameTextBox"
Text="{Binding Path=FirstName, UpdateSourceTrigger=PropertyChanged}"
Width="200"
Margin="0,4"
/>
<TextBox
x:Name="lastNameTextBox"
Text="{Binding Path=LastName, UpdateSourceTrigger=PropertyChanged}"
Width="200"
Margin="0,4"
/>
<TextBlock
x:Name="fullNameTextBlock"
Text="{Binding FullName}"
Background="LightBlue"
Margin="0,4"
/>
</StackPanel>
That XAML is almost as short as in the original version. However, in this example, there is no plumbing code wiring the controls up to the data source. Most data binding scenarios in WPF use this approach. Using the Binding
markup extension feature vastly simplifies your XAML, and allows you to spend time working on more important things.
Conclusion
There are many ways to hook a user interface up to data. None of them are wrong, and all of them are useful in certain situations. Most of the time, WPF developers use data binding via the convenient markup extension syntax. In more complicated, dynamic scenarios, it can be useful to create bindings in code. I hope that this article has shed some light on the topic, so that you can make an informed decision about how you want to get the job done.