Data Binding
Download the tutorial in PDF formatBy Jesse Liberty  Download the code

Data Binding

Data binding is a connection between the User Interface and a business object or other data provider. The User Interface object is called the target, the provider of the data is called the source.

Data-binding assists with the separation of the User Interface level of your application from the other layers of  your application (business objects, data, and so forth). This separation of responsibility is further reinforced by decoupling the UI target from its source through the the use of a Binding object.

The binding object can be thought of as a black box with a universal connectors on one side for the target and on the other side for the source. There are switches on top, the most important of which is the Data Binding Mode switch which determines which way the data will flow.

Data Binding Modes

The Mode (which is of type BindingMode) is an enumeration with three possible values as shown here,

 

OneTime binding sets the target and then the binding is completed. This is great for displaying data that rarely or never changes

OneWay binding  sets the target and keeps it up to date as the source changes. This is great for displaying data that the user is not permitted to change.

TwoWay binding sets the target and keeps the target up to date as the source changes and keeps the source up to date as the user changes the target or changes something else in the application that will cause your application to change the source.

If you were building an on line bookstore and were displaying information about a book, you might use OneTime binding for the Title and Author (once you get them, they are not going to change) and OneWay binding for the price (someone might mark down the price during the day) but you’d want TwoWay binding for the Quantity on hand.

The target of your binding can be any public property of virtually any CLR object (for the minor restrictions on this, see the Afterward).

You can see this by building a small example; but even in this stripped down exercise, we’ll keep to a basic 3-tier approach being sure to keep a relatively strict separation among

  • User Interface Layer
  • Business Layer
  • Persistence Layer

The User Interface layer will consist of controls that we will obtain from the toolbox and use as offered for now, though a future tutorial will demonstrate how to change their appearance using styles and templates.

The Business Layer will be represented by a Book class

We will ignore the persistence layer for now, though this will be covered in great detail in future tutorials.

 

The Business object and INotifyPropertyChanged

Create a new Silverlight Application, which will create a Page.xaml and a Page.xaml.cs.

Add to the application a Book.cs file which will represent the business layer.

What separates a Silverlight Business object from one created for (e.g., ASP.NET) is that we want to have our business object participate in oneway or twoway binding with the UI layer. To do so, it must implement the INotifyPropertyChanged interface.

This interface requires only one thing: that the class have an event of type PropertyChangedEventHandler (named PropertyChanged by convention),  Implicit in supporting binding, however, is that your business object must, by convention, fire the the PropertyChanged event when any property that is tied to a UI control is set.

Let’s begin with a simplified version of the Book class,

 

The first thing to notice is the using statement for System.ComponentModel on line 1, necessary for the interface INotifyPropertyChanged.  The promise to implement the interface is on line 5 and the fulfillment of that promise is on line 10.

The property we are exposing is Title, on line 12, and the implementation to keep the target in sync begins on line 15. When a new value is to be set, first the local backing variable is set as normal, then if the event is not null, the method the event’s delegate encapsulates is called with a new instance of a PropertyChangedEventArgs created whose only argument is the name of the property.

A better implementation of Book.cs

Best practices would be to split out the creation of the PropertyChangedEventArgs call so that you can use it for more than one property in the Book class.

 

It’s easy to see that by factoring out the call to PropertyChanged, we can now pass in the name of any property and reuse this boilerplate to invoke the delegate. We’ll demonstrate this by adding a second property, the author’s name,

 

With this much of our book class in place and with two properties we can call, our Business class is good to go.

The UI will display this information in a pair of TextBlocks within the provided grid. Since there are thousands of books in the on line store, the TextBlocks can know that they are going to bind to the Title and Author properties respectively, but they can’t know at design time which book will be the source. That will have to be determined at run time and set in code.

Therefore, we’ll assign to the Text property of the TextBlock a Binding object and we’ll tell that Binding object the Property it will use (but not the source). We can explicitly set the Mode (a good practice) or let it default to OneWay.

At run time we need to tell each Binding object what its data source is, by setting each TextBox’s DataContext.

DataContext

When you DataBind you tell the target some of what it needs to know at design time (e.g., you might tell a TextBlock that it will be displaying the Title of a book) but you don’t want to tell it exactly which book’s title it will be displaying. The DataContext is the specific book, chosen at run time, and assigned to the DataContext property of the Framework Element (in this case the TextBlock) so that it knows “Oh, I get the Title from this book”  More on this shortly.

The DataContext can be raw data, but far more common is to assign an object of type Binding. A Binding object knows how to get the data needed by the target from the source. It is our universal connector with the Mode switch on top.

Another advantage of using a DataContext is that it allows elements to inherit information about the data source from the parent element where it makes sense to do so.

Presumably some action by the user would select a book, and the Book business object would be assigned as the DataSource for the TextBlock.

To keep the example simple, we will just create a book (line 18) and assign a title to it (line 19) and then assign that book as the DataContext of the Title on line 20.

Pop Quiz: Whose Data Context just got set?

There are three reasonable answers, and it turns out to be the least immediately intuitive for many folks, and yet this is a very common naming convention.

1.       The property Title that we set on line 19

2.       The attribute referred to by Text=”{Binding Title}” on line 11 in the lower pane

3.       The Textblock x: Title, also on line 11.

Perhaps somewhat surprisingly the answer is #3, which you can easily prove, by changing the names to AA and TT,

 

I point out this potential area of confusion because almost all the documentation, books and code you’ll read will use the same name for the control, and for the property, and as long as you are clear about how it works it need not be confusing, though an argument could be made for a differentiating convention (e.g, Title and TitleControl) but such thoughts set off long rancorous discussions on newsgroups that can be great fun when you can’t sleep.

 

The Logic of Data Binding Step By Step

1.       Create a target object (e.g, TextBlock) that  and identify its Dependency Property that will be passed to Binder (e.g., Text).

2.       Identify the Property name from a source that implements INotifyPropertyChanged (e.g.,Book)  and a property that calls the PropertyChanged Event when its value is set (e.g., Title).

3.       Map the Target to the Source’s property using a DataContext in the code-behind.

It’s easier than it sounds, especially the second time.

The XAML file has all the UI that we can know at design time but no more.. In this sample, we’ll use two TextBlocks to stand in for the complete UI of a real program. 

The TextBlock is ideal to read-only fields (such as Title and Author). We want our Silverlight application to be able to display the details of any book that might be chosen, so we don’t want to hardcode the title and author,

That will work, as long as you only have one book. Instead, we want the Text to be determined at run time. To make this work with whatever book is chosen, we’ll tell the Text field to use a Binder.

The Binder defaults to OneWay as its Mode (though we can (and should?) set this explicitly). We tell the Binder which property it maps to (Title, Author), though we do not tell it which object it connects to as we cannot – we won’t know until run-time.

The object it will connect to at run-time is the  data context, and of course the data context must have the appropriate properties.

So, for example, the Title text block knows that it is bound to a Title value, but it has no idea whose Title property. And that is just as it should be.

For convenience, in this example we create the book which will be the DataContext in the OnLoaded event handler and we gin up a book out of thin air, but all of that is just a stand in for what would really happen; which is that the user would somehow indicate which book is wanted, and an event handler would be called which would be responsible for creating or populating the book and then making it the data source.

 

The key to the Binding, however, is to make the business object (the Book) the DataContext for the two TextBlocks.

That completes the binding; now we have targest (the TextBlocks) each with a Binding. Each binding has a DataContext (the book) which  has the appropriate Property (Title and Author respectively). thus we can display  the information:

 

Testing INotifyChangedProperty

If the Book information were to change, the fact that Book implements INotifyChangedProperty would cause the UI to update. You can test this quickly as follows.

1.       Add a third row to the Grid and Add a Button whose name is Change and whose Content is Change Book as shown,

2.       In code-behind, make the Book a member variable, (so it can be accessed from any method).  and move its instantiation to the constructor Wire up and implement the Change button’s click method to change the title and author of the book.

 

3.       Note that when the book’s properties change,  the UI is updated automatically through responding to the event.

 

Data Contexts are Inherited

Rather than setting the DataContext individually for the Title and the Author, we notice that both are child  elements of the same grid. That allows us to assign the book as the Data context of the grid and both the Title and Author will “inherit” thie Grid’s data context unless either or both set their own.

 

Two Way Binding

Two way binding allows you to ensure that the updates work in both directions. That is, when the source is updated, the target is updated, but when the target is updated, the source is updated. This is critical for interactive applications.

This of course is much more difficult.. So sit down. Here’s what you have to do.

First, You’ll need to change one of your TextBlocks to a TextBox which is a much better UI element for text entry. In this example we’ll make the Author a TextBox. Second we’ll need to change the Mode to TwoWay.  Okay, the hard part is over.

When you start the application it will fill the text box with the name currently recorded in the book object as the value in the Author property. If you change what is in the text box, and leave the text box, the new data will be inserted into the Bok object. Honest.

Since I know you won’t believe me, (actually, I could be lying; how would you know? I could say it changed the book, but how could you really be sure?  So let’s make sure.) add another TextBlock named AuthorOut to the UI. We’ll have it show what is in the author field. That way if the book is updated, this should reflect the change. While we’re at it, let’s give the grid a second column so that it looks a bit tidier.

With that in place, we can put the Author TextBox (for input) next to the Author TextBlock (showing the state of the object). That is all we need  to verify that after you change the Author’s name, it is  in fact updated in the Book object,

Notice that both of these UI elements bind to the Author property, the first binding in TwoWay mode to allow changes made in the UI to update the Book, the second binding OneWay for display.

Start the application. Now click in the text box and change the authors name and then leave the text box. The output reflects that the book was changed (and by being changed, notified the UI to update itself with the new information).

 

Expanding the Book Class

Let’s expand the Book class to add a few more properties that might be reflected in other UI controls, including a data bound UI control. Here is what an instance of a book might look like,

The significant properties of this book are reflected in the properties of the Book Business object, along with at least one Business property not immediately obvious from the tangible item itself (quantity on hand)

 

Displaying the New Properties

To get going, let’s create a prompt using a DataTextBlock for each of the  new properties, and add display controls as shown in the following table

Book Property

Control

Notes

quantityOnHand

TextBox

Two Way

multipleAuthor

CheckBox

Two Way

Chapters

ListBox

One Way, Data Bound

The steps to displaying these properties are to add three new rows in the data grid and then to add a TextBlock for each prompt (bound to the Book) and the appropriate control for each of the new types.

We start by modifying the Grid, to allow extra rows

    

 

    Next we add the paired controls: one for each prompt, and one for each property,

      Not much is new here but there are a few minor but important things to notice:

  • A convention is created that the label and the value are given paired names, such as TitlePrompt and Title, AuthorPrompt and Author. This makes predicting control names easier, and thus maintenance easier.
  • The Value TextBlock gets its value from a Binding object whose name is the same as the name of the control (thus the Property that feeds Author is the Author property).
  • Mode is explicitly set rather than relying on the default value of OneWay

 

Also note that I’ve decided to explicitly align all controls vertically along the bottom, all prompts on the right edge of the column, and all values along the left of the column.

We’re now ready to use new controls for the new properties. Let’s skip over the chapters for a moment and go on to the MultipleAuthors prompt. This is our first two-way prompt: a checkbox.

The CheckBox is bound to the Boolean value MultipleAuthor, and a two way connection is established just by setting the Mode. As noted earlier, that’s all you have to do. If the user changes it to checked, the underlying data object (the book) will have its data changed (the MultipleAuthor property will change from false to true).

To see this, we’ll add a new button, Change that will toggle between displaying two different book objects

As you can see, there’s nothing special about the button; the magic is in the code. We accomplish this small miracle in small steps. First, pull the reference to the Book out into a member variable, second create three new member variables

You’ll initialize the two books in memory and have the first referred to by b1 and the second referred to by b2, and currentBook will toggle between them. A hack, I admit, but it will work and will keep the code simple.

The premise here is to mimic the idea that in a “real” system you’ll be picking one book not from two, but from many,

As you initialize each book, you’ll populate the book’s properties, including whether or not there are multiple authors,

In this version of the program, we’ll pay attention to the Boolean, but we won’t parse the string of author names. In a more sophisticated version we might use a collection of author names, or other more extensible solution.

TextBox

In addition to adding a CheckBox we add a second Read/Write field, the TextBox, which will display and allow the user to update the number of copies of the book on hand.

In our design, each book knows how many copies of itself are in the store; there certainly are other ways of designing this.

ListBox and Binding to a List

Finally, we come to the Chapters. The Book object defines the Chapters as a list of strings

You initialize the names of the chapters when you initialize the book (though, again, presumably this would be obtained from a database or web service),

When the book is displayed, the chapters will be displayed in the list box. When a new book is chosen, that new book’s chapters will be displayed. You could iterate through the new book’s chapters and create a new set of ListItems, but again that is error prone and doesn’t scale well. Once again, Data-binding is a more satisfactory solution.

Since the DataSource for the Title and Author (the current book) will also have the correct list of Chapters, you can assign the Chapter property of the Book to the ItemSource property of the List Box, and as the DataSource is changed, the chapters will be changed appropriately,

The next two images show the new details of the two books displayed as the user switches among them.

 

Afterword

It isn’t quite true that you can bind to any CLR Object; there are actually two restrictions, though they are almost never a problem. The first is that the target must be a FrameeworkElement. FrameworkElement inherits directly from UIElement and is an ancestor to all the visible UI elements you’ll want to bind to, as shown here,

 

FrameworkElement has the DataContext property you’ve seen in use above.

The second restriction is that the property you assign as the target must be a Dependency Property.

Dependency Properties

Don’t panic;  just about all the properties you want to bind to are dependency properties, and dependency properties are great. In fact, they are used all over Silverlight.

Silverlight 2, (like WPF) extends object properties using the Silverlight 2 property system.

Any property that is extended in this way is called a Dependency Property.

Dependency Properties are an incredibly powerful part of Silverlight. The essence of Dependency properties is that their value is determined at run time based on a confluence of factors, each evaluated in a specific order. These factors include:

  • Themes
  • User preferences
  • Data binding
  • Storyboards and animation
  • Templates and styles
  • Parent/child relationships
  • The results of callbacks

Dependency properties deserve and will receive their own complete tutorial, but a very brief overview will help with understanding data-binding.

Pay No Attention To The Type Behind The Property

The key to dependency properties is that each Dependency Property is backed by a type rather than the standard approach of backing a property with a private member variable.  Somewhat confusingly, the name of the type is DependencyProperty.

The other major player in the Silverlight property system is the DependencyObject: the base class that enables the Silverlight property services on its many derived objects:

An instance of a Dependency Property is called a Dependency Property Identifier, and is typically exposed as a static readonly member of the type that holds the dependency property.  This is usually the point where your eyes glaze over and you go off shaking your head and looking for an ice cream.  I find a table of terms can help:

 

Term

Definition

Dependency property

A property that is backed by a DependencyProperty

Dependency property identifier

An instance of a DependencyProperty

CLR Wrapper

The get and set  for the property.  See the example IsSpinning just below.

DependencyObject

Base class of all the objects that participate in the Silverlight dependency property system.

 

The following example of the IsSpinningProperty is from the Silverlight help files

 

In the small example shown above IsSpinningProperty is a DependencyProperty. It also provides a CLR Wrapper IsSpinning. The getter gets and casts the IsSpnningProperty and the setter calls SetValue on IsSpinningProperty passing in the value to set.

Setting Dependency Values in XAML

Because XAML uses Type Converters, you can typically simply assign a string value to a XAML attribute for Dependency values, as you are probably used to doing for the Background value for the Canvas

Setting values for Dependency Properties is greatly simplified by the get and set implementations exposed by the CLR wrappers,

In the code above, LGM is the canvas defined in XAMAL in the previous image. The value in LGM cut to 80% of its original value through the set implementation of the CLR wrapper; though that is invisible to the programmer.

Using the Documentation to Find Dependency Properties

You can tell that the Canvas’s Background property is a Dependency property by looking at the Canvas’s base class: Panel. Examining Panel’s Members (shown abridged here), reveals the key, Background is matched by BackgroundProperty.

You can identify Dependency Properties by the fact that the class they are a member of will have a field of the same name but appended with Property (and that is of type DependencyProperty.

Clicking on BackgroundProperty will bring you to its definition showing that it is in fact of type DependencyProperty.

 

To spot check, you might open up TextBox. You know that you’re likely to want to data-bind to the Text property. A quick look at the property list finds no TextProperty property. An easy mistake. You need to check the Fields, and sure enough, there it is,