Data binding, in its purest sense, is the capability of a control to be wired to a data source such that the control (a) displays certain items from that data source and (b) is kept in sync with the data source. After the connection is made, the runtime handles all the work necessary to make this happen. It doesn’t really matter where or how the data is stored. It could be a file system, a custom collection of objects, a database object, and so on.
Let’s look briefly at how we can establish a data binding connection using WPF. The key class here is System.Windows.Data.Binding
. This is the mediator in charge of linking a control with a data source. To successfully declare a binding, we need to know three things:
What UI control property do we want to bind?
What data source do we want to bind to?
And, within the data source, what specific element or property or such holds the data we are interested in?
We can bind to either single objects (such as binding a string property on an object to a text box) or to collections of objects (such as binding a List<>
collection to a list box). Either way, the mechanics remain the same.
Binding binding = new Binding();
binding.Source = _stringList;
listBox1.SetBinding(ListBox.ItemsSourceProperty, binding);
The preceding code snippet creates a Binding
object, sets the source of the Binding
object to our List<string>
collection, and then calls SetBinding
on our control (a list box), passing in the exact property on the control we want to bind to our data source and the Binding
object instance.
We can also assign data sources into a special object called the data context. Every FrameworkElement
object, and those that derive from that class, implements its own DataContext
instance. You can think of this as a global area where controls can go to get their data when participating in a data binding arrangement.
This ends up simplifying our data binding code quite a bit. We can set the context in our Window constructor like this:
this.DataContext = _stringList;
Now, we just point our ListBox
to this data context using a tag within the ListBox
’s XAML element.
<ListBox Name="listBox1" ItemsSource="{Binding}" />
The Binding
object in this case automatically hunts for objects stashed within a data context somewhere within the object tree. When it finds one, it automatically binds the objects.
This works great for our simple List<string>
example, but what if we are trying to bind a collection of custom objects to the list box? If we have a simple Employee
class with a Name
property and a PhoneNbr
property, how could we bind to a collection of those objects and show the employee name? Our process would actually remain the same. If we create an Employee
class and then create a List<Employee>
collection, all this code still works. But there is a problem. Figure 21.21 highlights an issue we have to solve.
We haven’t yet told the binding engine how exactly we want our data to be represented within the list box. By default, the binding process simply calls ToString
on every object.
One quick remedy is to simply override the ToString
method.
public override string ToString()
{
return _name;
}
This corrects the problem in this instance. But a more robust approach involves the use of a DataTemplate
. We cover that approach a little later, in the section “Building a Simple Image Viewer Application.”