Tải bản đầy đủ (.pdf) (32 trang)

Data Binding and Silverlight List Controls

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (311.18 KB, 32 trang )

C H A P T E R 5

■ ■ ■

105


Data Binding and Silverlight
List Controls
The previous chapter focused on the form controls contained in Silverlight. In this chapter, you will look
at two controls that are made to display lists of data: the ListBox and DataGrid. These controls are
typically bound to data through a technique known as data binding, which I’ll explore first.
Data Binding
Through data binding, UI elements (called targets) are “bound” to data from a data source (called the
source), as illustrated in Figure 5-1. When the data sources change, the UI elements bound to those data
sources update automatically to reflect the changes. The data can come from different types of sources,
and the target can be just about any UI element, including standard Silverlight controls.

Figure 5-1. Data binding in Silverlight
CHAPTER 5 ■ DATA BINDING AND SILVERLIGHT LIST CONTROLS

106

Data binding simplifies application development. Since changes are reflected automatically, you do
not need to manually update the UI elements. Also, by using data binding, you are able to separate the
UI from the data in your application, which allows for a cleaner UI and easier maintenance.
The Binding Class
Data binding in Silverlight is accomplished by using the Binding class. The Binding class has two
components—the source and target—and a property that defines the way the two are bound, called the
binding mode. The source is the data that is to be bound, the target is a property of the control that the
data is to be bound to, and the mode defines how the data is passed between the source and the target


(one-way, one-time, or two-way). You’ll see how this works in the upcoming exercise.
To define the binding of a control’s property, you use XAML markup extensions, such as {Binding
<path>}. For example, to bind the Text property of a TextBox to a data source’s FirstName element, you
would use the following XAML:
<TextBox Text="{Binding FirstName }" />
Try It Out: Simple Data Binding in Silverlight
To help explain data binding in Silverlight, let’s build a very simple application. The application will
include a Book object that contains two properties: Title and ISBN. These properties will be bound to two
TextBox controls. Figure 5-2 shows the end result of the example.

Figure 5-2. Simple data binding example
CHAPTER 5 ■ DATA BINDING AND SILVERLIGHT LIST CONTROLS

107

1. Create a new Silverlight application in Visual Studio 2008. Name the project
BasicDataBinding, and allow Visual Studio to create a Web Site project to host
your application.
2. Edit the MainPage.xaml file to define two columns and six grid rows. Place a
TextBlock in each row in column 1 and a TextBox in each row in column 2. Also
add some margins and some alignment assignments to improve the layout.
The code for the page follows:
<UserControl x:Class="BasicDataBinding.MainPage"
xmlns="
xmlns:x="
Width="400" Height="300">
<Grid x:Name="LayoutRoot" Background="White">

<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />

<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>

<TextBlock Text="Book Title"
VerticalAlignment="Center"
Margin="5" />
<TextBlock Text="ISBN-13"
VerticalAlignment="Center"
Margin="5"
Grid.Row="1" />

<TextBox Text="{Binding Title}"
Height="24"
Margin="5"
Grid.Column="1" />
<TextBox Text="{Binding ISBN}"
Height="24"
Margin="5"
Grid.Column="1" Grid.Row="1" />

<TextBlock Text="Book Title"
VerticalAlignment="Center"

Margin="5"
Grid.Row="2" />
<TextBlock Text="ISBN-13"
VerticalAlignment="Center"
CHAPTER 5 ■ DATA BINDING AND SILVERLIGHT LIST CONTROLS

108

Margin="5"
Grid.Row="3" />

<TextBox Text="{Binding Title}"
Height="24"
Margin="5"
Grid.Column="1" Grid.Row="2" />
<TextBox Text="{Binding ISBN}"
Height="24"
Margin="5"
Grid.Column="1" Grid.Row="3" />

</Grid>
</UserControl>
3. Next, edit the code behind, MainPage.xaml.cs. Add a Loaded event handler for
the application, which will fire when the application is loaded by the client.
This is accomplished with the following source code:
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();

this.Loaded += new RoutedEventHandler(Page_Loaded);
}

void Page_Loaded(object sender, RoutedEventArgs e)
{

}
}
Now you need to add a class to define a Book object. Below the MainPage class,
add the following class definition:
namespace BasicDataBinding
{
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
this.Loaded += new RoutedEventHandler(Page_Loaded);
}

void Page_Loaded(object sender, RoutedEventArgs e)
{

}
}

public class Book
CHAPTER 5 ■ DATA BINDING AND SILVERLIGHT LIST CONTROLS

109


{
public string Title { get; set; }
public string ISBN { get; set; }
}
}
4. Now that you have Book defined, you need to create an instance of Book and set
it to the LayoutRoot’s DataContext, as follows:
void Page_Loaded(object sender, RoutedEventArgs e)
{
Book b = new Book() {
Title = "Beginning Silverlight 3: From Novice to Professional",
ISBN = "978-1590599525" };

this.LayoutRoot.DataContext = b;
}
When you set up binding definitions for different controls, the controls do not
know where they are going to get their data. The DataContext property sets the
data context for a control that is participating in data binding. The DataContext
property can be set directly on the control. If a given control does not have a
DataContext property specified, it will look to its parent for its data context. The
nice thing about this model is that if you look above in the XAML for the page,
you will see little indication of where the controls are getting their data. This
provides an extreme level of code separation, allowing designers to design XAML
UIs and developers to work alongside the designers, defining the specifics of
how the controls are bound to their data sources.
5. At this point, you can go ahead and start debugging the application. If all goes
well, you will see the four text boxes populated with the data from the Book’s
instance (see Figure 5-2).
6. With the application running, change the book title in the first text box to just

“Beginning Silverlight,” by removing the “From Novice to Professional.”
You might expect that, since the third text box is bound to the same data, it will
automatically update to reflect this change. However, a couple of things need
to be done to get this type of two-way binding to work.
One problem is that, currently, the Book class does not support notifying
bound clients of changes to its properties. In other words, when a property
changes in Book, the class will not notify the TextBox instances that are bound
to the class of the change. You could take care of this by creating a change
event for each property. This is far from ideal; fortunately, there is an interface
that a class can implement that handles this for you. This interface is known as
INotifyPropertyChanged. Let’s use it.
7. Modify the Book class definition to inherit from INotifyPropertyChanged.
Notice that when you inherit from INotifyPropertyChanged, you need to add
using System.ComponentModel. Luckily, Visual Studio will help you with this, as
shown in Figure 5-3.
CHAPTER 5 ■ DATA BINDING AND SILVERLIGHT LIST CONTROLS

110


Figure 5-3. Visual Studio assists when you need to add the System.ComponentModel namespace.
Next, you can let Visual Studio do some more work for you. After adding the
using System.ComponentModel statement, right-click INotifyPropertyChanged
and choose the Explicitly implement interface INotifyPropertyChanged option,
as shown in Figure 5-4.

Figure 5-4. Visual Studio also assists in implementing the INotifiyPropertyChanged interface.
Now Visual Studio has added a new public event to your class:
public class Book : INotifyPropertyChanged
{

public string Title { get; set; }
public string ISBN { get; set; }

#region INotifyPropertyChanged Members

public event PropertyChangedEventHandler PropertyChanged;

#endregion
}
8. Next, you need to create a convenience method that will fire the
PropertyChanged event. Call it FirePropertyChanged, as shown in the following
code.
public class Book : INotifyPropertyChanged
{
public string Title { get; set; }
public string ISBN { get; set; }

#region INotifyPropertyChanged Members

void FirePropertyChanged(string property)
CHAPTER 5 ■ DATA BINDING AND SILVERLIGHT LIST CONTROLS

111

{
if (PropertyChanged != null)
{
PropertyChanged(this,
new PropertyChangedEventArgs(property));
}

}

public event PropertyChangedEventHandler PropertyChanged;

#endregion
}
9. Now you need to extend the simplified properties by adding private members
and full get/set definitions to define the get and set operations, as shown in
the following code. The get is just like a normal get operation, where you
simply return the internal member value. For the set, you first set the internal
member value, and then call the FirePropertyChanged method, passing it the
name of the property.
public class Book : INotifyPropertyChanged
{
private string _title;
private string _isbn;

public string Title
{
get
{
return _title;
}
set
{
_title = value;
FirePropertyChanged("Title");
}
}


public string ISBN
{
get
{
return _isbn;
}
set
{
_isbn = value;
FirePropertyChanged("ISBN");
}
}

CHAPTER 5 ■ DATA BINDING AND SILVERLIGHT LIST CONTROLS

112

#region INotifyPropertyChanged Members

void FirePropertyChanged(string property)
{
if (PropertyChanged != null)
{
PropertyChanged(this,
new PropertyChangedEventArgs(property));
}
}

public event PropertyChangedEventHandler PropertyChanged;


#endregion
}
With this completed, your class is set up to notify bound clients of changes to
the Title and ISBN properties. But you still need to take one more step. By
default, when you bind a source to a target, the BindingMode is set to OneWay
binding, which means that the source will send the data to the target, but the
target will not send data changes back to the source. In order to get the target
to update the source, you need to implement two-way (TwoWay) binding.
■ Note Earlier, I mentioned that there are three options for
BindingMode
. The third option is
OneTime
binding. In
this mode, the values are sent to the target control property when the object is set to the
DataContext
. However,
the values of the target property are not updated when the source value changes.
10. To change to two-way binding, add the Mode=TwoWay parameter when defining
the {Binding} on a control, as follows:
<TextBlock Text="Book Title"
VerticalAlignment="Center"
Margin="5" />
<TextBlock Text="ISBN-13"
VerticalAlignment="Center"
Margin="5"
Grid.Row="1" />

<TextBox Text="{Binding Title, Mode=TwoWay}"
Height="24"
Margin="5"

Grid.Column="1" />
<TextBox Text="{Binding ISBN, Mode=TwoWay }"
Height="24"
Margin="5"
Grid.Column="1" Grid.Row="1" />

<TextBlock Text="Book Title"
CHAPTER 5 ■ DATA BINDING AND SILVERLIGHT LIST CONTROLS

113

VerticalAlignment="Center"
Margin="5"
Grid.Row="2" />
<TextBlock Text="ISBN-13"
VerticalAlignment="Center"
Margin="5"
Grid.Row="3" />

<TextBox Text="{Binding Title, Mode=TwoWay }"
Height="24"
Margin="5"
Grid.Column="1" Grid.Row="2" />
<TextBox Text="{Binding ISBN, Mode=TwoWay }"
Height="24"
Margin="5"
Grid.Column="1" Grid.Row="3" />
11. Rebuild and run your application. Update any of the fields, and leave the focus
on the control. You’ll see that the two-way binding is triggered, and the
corresponding field is also updated, as shown in Figure 5-5.


Figure 5-5. Two-way binding in action
Congratulations! You have just created a Silverlight application that allows for two-way data
binding. We will now move on to look at data binding lists of data to the two list controls provided in
Silverlight: DataGrid and ListBox.
CHAPTER 5 ■ DATA BINDING AND SILVERLIGHT LIST CONTROLS

114

Element to Element Binding
In addition to binding to data, elements can be bound directly to other elements, which can significantly
improve the readability and efficiency of your code. The syntax for binding to an element is very similar
to binding to a data item, the only difference is that in the binding an ElementName is specified, which
is very much like setting the ItemsSource to the Element. As an example, if you wanted to bind the
IsEnabled property of a control to a checkbox’s IsChecked property. Assuming the checkbox is named
EnableButton, the binding syntax would be the following.
IsEnabled="{Binding IsChecked, Mode=OneWay, ElementName=EnableButton}"
Notice that the binding is the same as it would be when binding to a data source, except that we have
added the ElementName=EnableButton. Let’s try this out in an exercise.
Try It Out: Element to Element Binding
To help explain element to element binding in Silverlight, let’s build a very simple application. The
application will include a button and a checkbox. When the checkbox is checked, the button is enabled,
when the checkbox is unchecked, the button is disabled. Let’s get started.
1. Create a new Silverlight application in Visual Studio 2008. Name the project
Ch5_ElementBinding, and allow Visual Studio to create a Web Site project to
host your application.
2. Edit the MainPage.xaml file to add a StackPanel to the root Grid. Place a
ToggleButton and CheckBox named EnableButton within that StackPanel so the
ToggleButton appears above the CheckBox. Add a margin of 20 on the
StackPanel and 5 on the ToggleButton and CheckBox to add some spacing

between the controls. The code for the page follows:
<Grid x:Name="LayoutRoot" Background="White">
<StackPanel Margin="20">

<ToggleButton
Margin="5" Content="Click to Toggle" />

<CheckBox
x:Name="EnableButton" IsChecked="true"
Margin="5" Content="Enable Button" />

</StackPanel>
</Grid>
3. Next, we need to bind the ToggleButton’s IsEnabled property to the
CheckBox’s IsChecked property. We will do this with one way binding as
described earlier in this chapter, and we will set the ElementName to
EnableButton, which is the name we gave our CheckBox. The updated source
code should now look like the following.
<Grid x:Name="LayoutRoot" Background="White">
<StackPanel Margin="20">

<ToggleButton
Margin="5" Content="Click to Toggle"
CHAPTER 5 ■ DATA BINDING AND SILVERLIGHT LIST CONTROLS

115

IsEnabled="{Binding IsChecked, Mode=OneWay,
ElementName=EnableButton}" />


<CheckBox
x:Name="EnableButton" IsChecked="true"
Margin="5" Content="Enable Button" />

</StackPanel>
</Grid>
4. That is it! No coding is required for this demo. Run the sample and will see that
the ToggleButton is enabled, as shown in Figure 5-6.

Figure 5-6. Element Binding example with Toggle Button Enabled
5. Now press uncheck the Enable Button checkbox and you will see that the
ToggleButton is no longer enabled, as shown in Figure 5-7.
CHAPTER 5 ■ DATA BINDING AND SILVERLIGHT LIST CONTROLS

116


Figure 5-7. Element Binding Example with Toggle Button Disabled
The DataGrid Control
The data grid type of control has been around for ages and has been the primary choice for developers
who need to display large amounts of data. The DataGrid control provided by Silverlight is not just a
standard data grid, however. It contains a great deal of rich user functionality that, in the past, has been
present only in third-party data grid components. For example, the Silverlight DataGrid handles resizing
and reordering of grid columns.
Figure 5-8 shows an example of a very simple DataGrid, where the columns were automatically
generated. Notice how the column titled Male is a check box. The DataGrid control has built-in
intelligence to automatically show Boolean data types as check box cells.

×