Data binding allows us to build data-driven applications in Silverlight in a much easier and much faster way compared to old-school methods of displaying and editing data. This article and the following one take a look at how data binding works. We'll start by looking at the general concepts of data binding in Silverlight 4 in this article.
Analyzing the term data binding immediately reveals its intentions. It is a technique that allows us to bind properties of controls to objects or collections thereof.
The concept is, in fact, not new. Technologies such as ASP.NET, Windows Forms, and even older technologies such as MFC (Microsoft Foundation Classes) include data binding features. However, WPF's data binding platform has changed the way we perform data binding; it allows loosely coupled bindings. The BindingsSource control in Windows Forms has to know of the type we are binding to, at design time. WPF's built-in data binding mechanism does not. We simply defi ne to which property of the source the target should bind. And at runtime, the actual data—the object to which we are binding—is linked. Luckily for us, Silverlight inherits almost all data binding features from WPF and thus has a rich way of displaying data.
A binding is defined by four items:
The data binding process can be summarized in the following image:
In the previous image, we can see that the data binding engine is also capable of synchronization. This means that data binding is capable of updating the display of data automatically. If the value of the source changes, Silverlight will change the value of the target as well without us having to write a single line of code. Data binding isn't a complete black box either. There are hooks in the process, so we can perform custom actions on the data fl owing from source to target, and vice versa. These hooks are the converters.
Our applications can still be created without data binding. However, the manual process—that is getting data and setting all values manually on controls from code-behind—is error prone and tedious to write. Using the data-binding features in Silverlight, we will be able to write more maintainable code faster.
In this article, we'll explore how data binding works. We'll start by building a small data-driven application, which contains the most important data binding features, to get a grasp of the general concepts. We'll also see that data binding isn't tied to just binding single objects to an interface; binding an entire collection of objects is supported as well. We'll also be looking at the binding modes. They allow us to specify how the data will flow (from source to target, target to source, or both). We'll finish this article series by looking at the support that Blend 4 provides to build applications that use data binding features.
In the recipes of this article and the following one, we'll assume that we are building a simple banking application using Silverlight. Each of the recipes in this article will highlight a part of this application where the specific feature comes into play. The following screenshot shows the resulting Silverlight banking application:
When building Silverlight applications, we often need to display data to the end user. Applications such as an online store with a catalogue and a shopping cart, an online banking application and so on, need to display data of some sort.
Silverlight contains a rich data binding platform that will help us to write data-driven applications faster and using less code. In this recipe, we'll build a form that displays the data of the owner of a bank account using data binding.
To follow along with this recipe, you can use the starter solution located in the Chapter02/ SilverlightBanking_Displaying_Data_Starter folder in the code bundle available on the Packt website. The finished application for this recipe can be found in the Chapter02/SilverlightBanking_Displaying_Data_Completed folder.
Let's assume that we are building a form, part of an online banking application, in which we can view the details of the owner of the account. Instead of wiring up the fields of the owner manually, we'll use data binding. To get data binding up and running, carry out the following steps:
public class Owner
{
public int OwnerId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Address { get; set; }
public string ZipCode { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Country { get; set; }
public DateTime BirthDate { get; set; }
public DateTime CustomerSince { get; set; }
public string ImageName { get; set; }
public DateTime LastActivityDate { get; set; }
public double CurrentBalance { get; set; }
public double LastActivityAmount { get; set; }
}
private Owner owner;
public MainPage()
{
InitializeComponent();
//initialize owner data
InitializeOwner();
}
private void InitializeOwner()
{
owner = new Owner();
owner.OwnerId = 1234567;
owner.FirstName = "John";
owner.LastName = "Smith";
owner.Address = "Oxford Street 24";
owner.ZipCode = "W1A";
owner.City = "London";
owner.Country = "United Kingdom";
owner.State = "NA";
owner.ImageName = "man.jpg";
owner.LastActivityAmount = 100;
owner.LastActivityDate = DateTime.Today;
owner.CurrentBalance = 1234.56;
owner.BirthDate = new DateTime(1953, 6, 9);
owner.CustomerSince = new DateTime(1999, 12, 20);
}
<Grid x_Name="OwnerDetailsGrid"
VerticalAlignment="Stretch"
HorizontalAlignment="Left"
Background="LightGray"
Margin="3 5 0 0"
Width="300" >
<Grid.RowDefinitions>
<RowDefinition Height="100"></RowDefinition>
<RowDefinition Height="30"></RowDefinition>
<RowDefinition Height="30"></RowDefinition>
<RowDefinition Height="30"></RowDefinition>
<RowDefinition Height="30"></RowDefinition>
<RowDefinition Height="30"></RowDefinition>
<RowDefinition Height="30"></RowDefinition>
<RowDefinition Height="30"></RowDefinition>
<RowDefinition Height="30"></RowDefinition>
<RowDefinition Height="30"></RowDefinition>
<RowDefinition Height="30"></RowDefinition>
<RowDefinition Height="30"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<Image x_Name="OwnerImage"
Grid.Row="0"
Width="100"
Height="100"
Stretch="Uniform"
HorizontalAlignment="Left"
Margin="3"
Source="/CustomerImages/man.jpg"
Grid.ColumnSpan="2">
</Image>
<TextBlock x_Name="OwnerIdTextBlock"
Grid.Row="1"
FontWeight="Bold"
Margin="2"
Text="Owner ID:">
</TextBlock>
<TextBlock x_Name="FirstNameTextBlock"
Grid.Row="2"
FontWeight="Bold"
Margin="2"
Text="First name:">
</TextBlock>
<TextBlock x_Name="LastNameTextBlock"
Grid.Row="3"
FontWeight="Bold"
Margin="2"
Text="Last name:">
</TextBlock>
<TextBlock x_Name="AddressTextBlock"
Grid.Row="4"
FontWeight="Bold"
Margin="2"
Text="Adress:">
</TextBlock>
<TextBlock x_Name="ZipCodeTextBlock"
Grid.Row="5"
FontWeight="Bold"
Margin="2"
Text="Zip code:">
</TextBlock>
<TextBlock x_Name="CityTextBlock"
Grid.Row="6"
FontWeight="Bold"
Margin="2"
Text="City:">
</TextBlock>
<TextBlock x_Name="StateTextBlock"
Grid.Row="7"
FontWeight="Bold"
Margin="2"
Text="State:">
</TextBlock>
<TextBlock x_Name="CountryTextBlock"
Grid.Row="8"
FontWeight="Bold"
Margin="2"
Text="Country:">
</TextBlock>
<TextBlock x_Name="BirthDateTextBlock"
Grid.Row="9"
FontWeight="Bold"
Margin="2"
Text="Birthdate:">
</TextBlock>
<TextBlock x_Name="CustomerSinceTextBlock"
Grid.Row="10"
FontWeight="Bold"
Margin="2"
Text="Customer since:">
</TextBlock>
<TextBlock x_Name="OwnerIdValueTextBlock"
Grid.Row="1"
Grid.Column="1"
Margin="2"
Text="{Binding OwnerId}">
</TextBlock>
<TextBlock x_Name="FirstNameValueTextBlock"
Grid.Row="2"
Grid.Column="1"
Margin="2"
Text="{Binding FirstName}">
</TextBlock>
<TextBlock x_Name="LastNameValueTextBlock"
Grid.Row="3"
Grid.Column="1"
Margin="2"
Text="{Binding LastName}">
</TextBlock>
<TextBlock x_Name="AddressValueTextBlock"
Grid.Row="4"
Grid.Column="1"
Margin="2"
Text="{Binding Address}">
</TextBlock>
<TextBlock x_Name="ZipCodeValueTextBlock"
Grid.Row="5"
Grid.Column="1"
Margin="2"
Text="{Binding ZipCode}">
</TextBlock>
<TextBlock x_Name="CityValueTextBlock"
Grid.Row="6"
Grid.Column="1"
Margin="2"
Text="{Binding City}">
</TextBlock>
<TextBlock x_Name="StateValueTextBlock"
Grid.Row="7"
Grid.Column="1"
Margin="2"
Text="{Binding State}">
</TextBlock>
<TextBlock x_Name="CountryValueTextBlock"
Grid.Row="8"
Grid.Column="1"
Margin="2"
Text="{Binding Country}">
</TextBlock>
<TextBlock x_Name="BirthDateValueTextBlock"
Grid.Row="9"
Grid.Column="1"
Margin="2"
Text="{Binding BirthDate}">
</TextBlock>
<TextBlock x_Name="CustomerSinceValueTextBlock"
Grid.Row="10"
Grid.Column="1"
Margin="2"
Text="{Binding CustomerSince}">
</TextBlock>
<Button x_Name="OwnerDetailsEditButton"
Grid.Row="11"
Grid.ColumnSpan="2"
Margin="3"
Content="Edit details..."
HorizontalAlignment="Right"
VerticalAlignment="Top">
</Button>
<TextBlock x_Name="CurrentBalanceValueTextBlock"
Grid.Row="12"
Grid.Column="1"
Margin="2"
Text="{Binding CurrentBalance}" >
</TextBlock>
<TextBlock x_Name="LastActivityDateValueTextBlock"
Grid.Row="13"
Grid.Column="1"
Margin="2"
Text="{Binding LastActivityDate}" >
</TextBlock>
<TextBlock x_Name="LastActivityAmountValueTextBlock"
Grid.Row="14"
Grid.Column="1"
Margin="2"
Text="{Binding LastActivityAmount}" >
</TextBlock>
</Grid>
public MainPage()
{
InitializeComponent();
//initialize owner data
InitializeOwner();
OwnerDetailsGrid.DataContext = owner;
}
The result can be seen in the following screenshot: