Table of Contents
In this article, you will learn the basic concepts of simple data binding in a Silverlight application. I have covered the different types of binding modes available and how to use them declaratively and programmatically. We will also see how to do binding for a collection, the importance of the INotifyPropertyChanged
interface method, and the ObservableCollection
class. Our ultimate goal is to fetch information from a back-end or from a .NET object and show it in the user interface.
These are some of my other articles on Silverlight technology:
Databinding is the process of establishing a connection between a source and target. In Silverlight databinding, the source is the CRL object and the target is Silverlight controls (XAML Elements). Let me show you a visual.
There are three types of data binding that happens in Silverlight applications between a source and target.
- OneTime data binding
- OneWay data binding (default mode)
- TwoWay data binding
OneTime data binding: As the name suggests, data binding happens between the source and target only once. In this binding, the source (CRL object) data will bind with the target (XAML element) only when the page executes the first time. Later on, any changes made in the source will not be reflected back in the target element. You will prefer to use this binding mode to reduce overhead if you know that the source property won’t change.
OneWay data binding: In this data binding, the source will immediately inform about changes to the target control. We will be using this binding only for frequently changed elements. This is the default mode.
TwoWay data binding: This happens in bidirectional mode. Whenever any change occurs in the backend or the CRL object, it will inform to the XAML controls immediately, and vice versa.
Binding in Silverlight requires three things:
- The first thing we need is target UI element’s property. This can be a
TextBox
control's Text
property or ListBox
control’s ItemsSource
property etc… You can call this the DependencyProperty
of a FrameworkElement
.
- The source object that contains the data that flows between the source and the target. The source can be any CLR object.
- A binding object to handle the communication between these two.
To implement data binding in XAML code, you need to implement a binding statement. Here is the syntax for how to use a binding statement in XAML:
The binding is created in XAML using the {Binding ...}
syntax.
<TextBox x:Name="tbFirstName" Text="{Binding Path=FirstName, Mode=OneTime}"
Grid.Column="2" Grid.Row="1"></TextBox>
The binding statement has many properties, but here is a list of frequently used properties of the Binding
statement:
Path
is the name of the source property to get the data from.
Mode
is the connection type (OneTime, OneWay, and TwoWay) between the source and the target.
Source
is the standard CLR object that contains the data.
Converter
is used to specify the converter object that is called by the binding engine to modify the data as it is passed between the source and the destination.
Converter Culture
specifies a parameter that can be passed to the conversion of the data.
Conversion Parameter
specifies a parameter that can be passed to the converter.
There is one more important thing in database binding, which is the DataContext
property. The DataContext
property is used to set or get the data context for a FrameworkElement
when it is participate in data binding.
Data context is inherited. If you set the data context on a parent element, all its children will use the same data context. A child element can override this behavior by setting the Source
property on its binding object or by setting its DataContext
, which will then apply to all its children.
The DataContext
property can be set in the parent control or for each child control. The only advantage of setting it in the parent control is, you don’t need to repeat it for each child control.
Here is an example of how to set the DataContext
property in the parent control and use it in the child controls.
BindingModesExamples.xaml
<UserControl x:Class="SampleCode.BindingModesExamples"
xmlns:local="clr-namespace:SampleCode"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" >
<UserControl.Resources>
<local:Employee x:Key="employeeInfo" FirstName="Anjaiah" LastName="Keesari"/>
</UserControl.Resources>
<Grid x:Name="LayoutRoot"
DataContext="{StaticResource employeeInfo}"
Background="LightCyan" Width="500" Height="300"
HorizontalAlignment="Left" >
<Grid.ColumnDefinitions >
<ColumnDefinition Width="100" />
<ColumnDefinition Width="100" />
<ColumnDefinition Width="200" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="100"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock Text="First Name" Grid.Column="1" Grid.Row="1"></TextBlock>
<TextBox x:Name="tbFirstName" Text="{Binding Path=FirstName, Mode=OneTime}"
Grid.Column="2" Grid.Row="1"></TextBox>
<TextBlock Text="Last Name" Grid.Column="1" Grid.Row="2"></TextBlock>
<TextBox x:Name="tbLastName" Text="{Binding Path=LastName, Mode=OneTime}"
Grid.Column="2" Grid.Row="2"></TextBox>
<TextBlock Text="Email ID" Grid.Column="1" Grid.Row="3"></TextBlock>
<TextBox x:Name="tbEmailID" Text="{Binding Path=EmailID, Mode=OneTime}"
Grid.Column="2" Grid.Row="3"></TextBox>
</Grid>
</UserControl>
Most of the times, you may not want to bind the data just using XAML; you can also do the same thing using your favorite programming language like C#. Binding can also be performed programmatically. What you need to do is just create a new binding object and call the SetBinding()
method to perform the binding between the source and the target. Here is a sample code to do that.
BindingModesExamples.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Data;
namespace SampleCode
{
public partial class BindingModesExamples : UserControl
{
public BindingModesExamples()
{
InitializeComponent();
Loaded+=new RoutedEventHandler(BindingModesExamples_Loaded);
}
private void BindingModesExamples_Loaded(object sender, RoutedEventArgs args)
{
Employee employee = new Employee();
employee.EmailID = "Keesari_anjaiah@yahoo.co.in";
Binding binding = new Binding()
{
Source = employee,
Path = new PropertyPath("EmailID"),
Mode = BindingMode.OneTime
};
tbEmailID.SetBinding(TextBox.TextProperty, binding);
}
}
}
Before we proceed further, let me show you the .NET object which I am using for each example. Do not worry about the PropertyChanged
concepts in this class which we will be talking about soon. Just continue reading this article completely in order to understand the data binding concepts.
Employee.cs
using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.ComponentModel;
namespace SampleCode
{
public class Employee :INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(PropertyChangedEventArgs e)
{
if (PropertyChanged != null)
PropertyChanged(this, e);
}
private int employeeID;
public int EmployeeID
{
get
{
return employeeID;
}
set
{
if (employeeID != value)
{
employeeID = value;
OnPropertyChanged(new PropertyChangedEventArgs("EmployeeID"));
}
}
}
private string firstName;
public string FirstName
{
get { return firstName; }
set
{
if (firstName != value)
{
firstName = value;
OnPropertyChanged(new PropertyChangedEventArgs("FirstName"));
}
}
}
private string lastName;
public string LastName
{
get { return lastName; }
set
{
if (lastName != value)
{
lastName = value;
OnPropertyChanged(new PropertyChangedEventArgs("LastName"));
}
}
}
private String emailID;
public String EmailID
{
get
{
return emailID;
}
set
{
if (emailID != value)
{
emailID = value;
OnPropertyChanged(new PropertyChangedEventArgs("EmailID"));
}
}
}
private string title;
public string Title
{
get { return title; }
set
{
if (title != value)
{
title = value;
OnPropertyChanged(new PropertyChangedEventArgs ("Title"));
}
}
}
private DateTime dateOfBirth;
public DateTime DateOfBirth {
get { return dateOfBirth; }
set {
if (dateOfBirth != value)
{
dateOfBirth = value;
OnPropertyChanged(new PropertyChangedEventArgs("DateOfBirth"));
}
}
}
}
}
Output:
Now that we are clear on single object data binding, let’s talk about collections of objects.
ListBox
is one of the controls used to bind collections of data. All collection control classes are represented by the ItemsControl
class. Binding a collection to an ItemsControl
is as simple as assigning the ItemsSource
property to some collection and assigning the DisplayMemberPath
to a property of a collection item.
TwoWayBindingExamples.xaml
<UserControl x:Class="SampleCode.TwoWayBindingExamples"
xmlns:local="clr-namespace:SampleCode"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006">
<UserControl.Resources>
<local:Employees x:Key="Employees" />
</UserControl.Resources>
<StackPanel DataContext="{StaticResource Employees}"
Background="LightCyan" Width="500" Height="300" >
<TextBox x:Name="tbDescription"
Text="{Binding Path=SelectedItem.Title, ElementName=lbEmployees, Mode=TwoWay}"
HorizontalAlignment="Left" VerticalAlignment="Top" Margin="10" Width="325" />
<ListBox x:Name="lbEmployees" ItemsSource="{Binding}"
DisplayMemberPath="Title" HorizontalAlignment="Left" VerticalAlignment="Top"
Margin="10" Width="323" />
</StackPanel>
</UserControl>
Employees.cs
using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Collections.ObjectModel;
namespace SampleCode
{
public class Employees : ObservableCollection<Employee>
{
public Employees()
{
this.Add(new Employee()
{
EmployeeID=1,
FirstName = "Nancy",
LastName = "Davolio",
Title = "Sales Representative",
});
this.Add(new Employee()
{
EmployeeID = 2,
FirstName = "Andrew",
LastName = "Fuller",
Title = "Vice President, Sales",
});
this.Add(new Employee()
{
EmployeeID = 3,
FirstName = "Janet",
LastName = "Leverling",
Title = "Sales Manager",
});
}
}
}
As we discussed earlier, we need to allow changes made in the data source to reflect immediately on the target. How is this possible? This is possible by implementing the INotifyPropertyChanged
interface. It is a descendent of ObservableCollection<T>
, and the interface is implemented for you. What you need to do is take the namespace System.ComponentModel
to implement INotifyPropertyChanged
interface. This has the single method called PropertyChanged()
. When setting a property value, you need to call the OnPropertyChanged()
method if any value changes.
To provide notifications for collection changes (new item added, removed, or entire list refreshed), we need to inherit our collection object from ObservableCollection<T>
. Add a reference to System.Collections.ObjectModel
before using ObservableCollection
.
Silverlight provides the ObservableCollection<T>
class, which is a base class data collection that implements the INotifyCollectionChanged
interface, as well as the INotifyPropertyChanged
interface. It also has the expected collection support, defined by deriving from the Collection<T>
class.
Note: Update occurs when the TextBox
loses focus.
Output:
I hope you enjoyed my article. Please do not forget to write your comments on this article, which is very important for me.