Tải bản đầy đủ - 0 (trang)
17-17. Use Data Templates to Display Bound Data

17-17. Use Data Templates to Display Bound Data

Tải bản đầy đủ - 0trang

CHAPTER 17 ■ WINDOWS PRESENTATION FOUNDATION



The Code

The following example demonstrates a window that contains a System.Windows.Controls.ListBox

control. The ItemsSource property of the ListBox is bound to a collection of Person objects. The Person

class is defined in the Data.cs file and exposes FirstName, LastName, Age, and Photo properties. It also

overrides the ToString method to return the full name of the person it represents. Without a

DataTemplate, the ListBox control would just display this list of names. Figure 17-14 shows what this

would look like.



Figure 17-14. Binding to a list of data objects without specifying a DataTemplate

However, the ItemTemplate property of the ListBox is set to a static resource called personTemplate.

This is a DataTemplate resource defined in the window’s System.Windows.ResourceDictionary. The

DataTemplate creates a System.Windows.Controls.Grid control inside a System.Windows.Controls.Border

control. Inside the Grid, it defines a series of System.Windows.Controls.TextBlock controls and a

System.Windows.Controls.Image control. These controls have standard binding statements that bind

their properties to properties on the Person class. When the window opens and the ListBox binds to the

collection of Person objects, the binding mechanism uses the set of UI elements in the DataTemplate to

display each item. Figure 17-15 shows the same ListBox as in Figure 17-14 but with its ItemTemplate

property set to the DataTemplate.

The XAML for the window is as follows:


x:Class="Apress.VisualCSharpRecipes.Chapter17.MainWindow"

xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

xmlns:local="clr-namespace:Apress.VisualCSharpRecipes.Chapter17"

Title="Recipe17_17" Height="298" Width="260">










x:Key="lblStyle"

TargetType="{x:Type TextBlock}">









845



www.it-ebooks.info



CHAPTER 17 ■ WINDOWS PRESENTATION FOUNDATION










x:Key="dataStyle"

TargetType="{x:Type TextBlock}"

BasedOn="{StaticResource lblStyle}">














BorderThickness="1"

BorderBrush="Gray"

Padding="4"

Margin="4"

Height="Auto"

Width="Auto">














Style="{StaticResource lblStyle}"

Text="First Name" />


Style="{StaticResource dataStyle}"

Text="{Binding Path=FirstName}"/>


Style="{StaticResource lblStyle}"

Text="Last Name" />


Style="{StaticResource dataStyle}"

Text="{Binding Path=LastName}" />


Style="{StaticResource lblStyle}"

Text="Age" />


Style="{StaticResource dataStyle}"

Text="{Binding Path=Age}" />





846



www.it-ebooks.info



CHAPTER 17 ■ WINDOWS PRESENTATION FOUNDATION




Margin="4"

Grid.Column="1"

Width="96"

Height="140"

Source="{Binding Path=Photo}"/>
















Margin="10"

ItemsSource="{Binding Source={StaticResource people}}"

ItemTemplate="{StaticResource personTemplate}"/>













Figure 17-15. Binding to a list of data objects and specifying a DataTemplate



847



www.it-ebooks.info



CHAPTER 17 ■ WINDOWS PRESENTATION FOUNDATION



17-18. Bind to a Collection with the Master-Detail Pattern

Problem

You need to bind to the items in a data collection and display more information about the selected item.

For example, you might display a list of product names and prices on one side of the screen and a more

detailed view of the selected product on the other side.



Solution

Bind a data collection to the ItemsSource property of a System.Windows.Controls.ItemsControl such as a

System.Windows.Controls.ListBox, System.Windows.Controls.ListView, or System.Windows.Controls.

TreeView. Implement System.Collections.Specialized.INotifyCollectionChanged on the data

collection to ensure that insertions or deletions in the collection update the UI automatically.

Implement the master-detail pattern by binding a System.Windows.Controls.ContentControl to the

same collection.



How It Works

To bind an ItemsControl to a collection object, set its ItemsSource property to an instance of a collection

class. This is a class that implements the System.Collections.IEnumerable interface, such as

System.Collections.Generic.List or System.Collections.ObjectModel.Collection, or the

System.Collections.IList and System.Collections.ICollection interfaces. However, if you bind to any

of these objects, the binding will be one-way and read-only. To set up dynamic bindings so that

insertions or deletions in the collection update the UI automatically, the collection must implement the

System.Collections.Specialized.INotifyCollectionChanged interface. This interface provides the

mechanism for notifying the binding target of changes to the source collection, in much the same way as

the System.ComponentModel.INotifyPropertyChanged interface notifies bindings of changes to properties

in single objects.

INotifyCollectionChanged exposes an event called CollectionChanged that should be raised

whenever the underlying collection changes. When you raise this event, you pass in an instance of the

System.Collections.Specialized.NotifyCollectionChangedEventArgs class. This contains properties

that specify the action that caused the event—for example, whether items were added, moved, or

removed from the collection and the list of affected items. The binding mechanism listens for these

events and updates the target UI element accordingly.

You do not need to implement INotifyCollectionChanged on your own collection classes. WPF

provides the System.Collections.ObjectModel.ObservableCollection class, which is a built-in

implementation of a data collection that exposes INotifyCollectionChanged. If your collection classes

are instances of the ObservableCollection class or they inherit from it, you will get two-way dynamic

data binding for free.



848



www.it-ebooks.info



CHAPTER 17 ■ WINDOWS PRESENTATION FOUNDATION



■ Note To fully support transferring data values from source objects to targets, each object in your collection that

supports bindable properties must also implement the INotifyPropertyChanged interface. It is common practice

to create a base class for all your custom business objects that implements INotifyPropertyChanged and a base

collection class for collections of these objects that inherits from ObservableCollection. This automatically

enables all your custom objects and collection classes for data binding.



To implement the master-detail scenario of binding to a collection, you simply need to bind two or

more controls to the same System.Windows.Data.CollectionView object. A CollectionView represents a

wrapper around a binding source collection that allows you to navigate, sort, filter, and group the

collection, without having to manipulate the underlying source collection itself. When you bind to any

class that implements IEnumerable, the WPF binding engine creates a default CollectionView object

automatically behind the scenes. So if you bind two or more controls to the same

ObservableCollection object, you are in effect binding them to the same default CollectionView

class. If you want to implement custom sorting, grouping, and filtering of your collection, you will need

to define a CollectionView explicitly yourself. You do this by creating a System.Windows.Data.

CollectionViewSource class in your XAML. This approach is demonstrated in the next few recipes in this

chapter. However, for the purpose of implementing the master-detail pattern, you can simply bind

directly to an ObservableCollection and accept the default CollectionView behind the scenes.

To display the master aspect of the pattern, simply bind your collection to the ItemsSource property

of an ItemsControl, such as a System.Windows.Controls.ListBox, System.Windows.Controls.ListView, or

System.Windows.Controls.TreeView. If you do not specify a DataTemplate for the ItemTemplate property

of the ItemsControl, you can use the DisplayMemberPath property to specify the name of the property the

ItemsControl should display. If you do not support a value for DisplayMemberPath, it will display the

value returned by the ToString method of each data item in the collection.

To display the detail aspect of the pattern for the selected item, simply bind a singleton object to the

collection, such as a ContentControl. When a singleton object is bound to a CollectionView, it

automatically binds to the CurrentItem of the view.

If you are explicitly creating a CollectionView using a CollectionViewSource object, it will

automatically synchronize currency and selection between the binding source and targets. However, if

you are bound directly to an ObservableCollection or other such IEnumerable object, then you will

need to set the IsSynchronizedWithCurrentItem property of your ListBox to True for this to work. Setting

the IsSynchronizedWithCurrentItem property to True ensures that the item selected always corresponds

to the CurrentItem property in the ItemCollection. For example, suppose there are two ListBox controls

with their ItemsSource property bound to the same ObservableCollection. If you set

IsSynchronizedWithCurrentItem to True on both ListBox controls, the selected item in each will

be the same.



The Code

The following example demonstrates a window that data-binds to an instance of the PersonCollection

class in its constructor. The PersonCollection class is an ObservableCollection of Person objects.

Each Person object exposes name, age, and occupation data, as well as a description.

In the top half of the window, a ListBox is bound to the window’s DataContext. This is assigned an

instance of the PersonCollection in the code-behind for the window. The ItemTemplate property of the



849



www.it-ebooks.info



Tài liệu bạn tìm kiếm đã sẵn sàng tải về

17-17. Use Data Templates to Display Bound Data

Tải bản đầy đủ ngay(0 tr)

×