Tải bản đầy đủ - 0 (trang)
17-18. Bind to a Collection with the Master-Detail Pattern

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

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

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



CHAPTER 17 ■ WINDOWS PRESENTATION FOUNDATION



ListBox references a DataTemplate called masterTemplate defined in the window’s Resources collection.

This shows the value of the Description property for each Person object in the collection. It sets the

UpdateSourceTrigger attribute to System.Windows.Data.UpdateSourceTrigger.PropertyChanged. This

ensures that the text in the ListBox item is updated automatically and immediately when the

Description property of a Person changes. In the bottom half of the window, a ContentControl binds to

the same collection. Because it is a singleton UI element and does not display a collection of items, it

automatically binds to the current item in the PersonCollection class. Because the

IsSynchronizedWithCurrentItem property of the ListBox is set to True, this corresponds to the selected

item in the ListBox. The ContentControl uses a DataTemplate called detailTemplate to display the full

details of the selected Person.

When the data displayed in the details section is changed, it automatically updates the

corresponding description in the master section above it. This is made possible for two reasons. First,

the System.Windows.Controls.TextBox controls in the details section specify a System.Windows.

Data.Binding.BindingMode of TwoWay, which means that when new text is input, it is automatically

marshaled to the binding source. Second, the Person class implements the INotifyPropertyChanged

interface. This means that when a value of a property changes, the binding target is automatically

notified.

At the bottom of the window, there is a System.Windows.Controls.Button control marked Add

Person. When this button is clicked, it adds a new Person object to the collection. Because the

PersonCollection class derives from ObservableCollection, which in turn implements

INotifyCollectionChanged, the master list of items automatically updates to show the new item.

The XAML for the window is as follows:


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

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

Title="Recipe17_18" Height="380" Width="280">




x:Key="masterTemplate">


Margin="4"

Text="{Binding

Path=Description,

UpdateSourceTrigger=PropertyChanged}"/>






BorderBrush="LightBlue"

BorderThickness="1">



















850



www.it-ebooks.info



CHAPTER 17 ■ WINDOWS PRESENTATION FOUNDATION










Margin="4"

Text="First Name"

VerticalAlignment="Center"/>


Text="{Binding Path=FirstName, Mode=TwoWay}"

Margin="4" Grid.Column="1"/>


Margin="4"

Text="Last Name"

Grid.Row="1"

VerticalAlignment="Center"/>


Margin="4"

Text="{Binding Path=LastName, Mode=TwoWay}"

Grid.Column="1" Grid.Row="1"/>


Margin="4"

Text="Age"

Grid.Row="2"

VerticalAlignment="Center"/>


Margin="4"

Text="{Binding Path=Age, Mode=TwoWay}"

Grid.Column="1"

Grid.Row="2"/>


Margin="4"

Text="Occupation"

Grid.Row="3"

VerticalAlignment="Center"/>


x:Name="cboOccupation"

IsEditable="False"

Grid.Column="1"

Grid.Row="3"

HorizontalAlignment="Left"

Text="{Binding Path=Occupation, Mode=TwoWay}"

Margin="4" Width="140">

Student

Engineer

Professional





851



www.it-ebooks.info



CHAPTER 17 ■ WINDOWS PRESENTATION FOUNDATION














VerticalAlignment="Center"

FontSize="14"

Margin="4"

Text="People"/>




ItemsSource="{Binding}"

ItemTemplate="{StaticResource masterTemplate}"

IsSynchronizedWithCurrentItem="True" />


VerticalAlignment="Center"

FontSize="14"

Margin="4"

Text="Details"/>




Content="{Binding}"

ContentTemplate="{StaticResource detailTemplate}" />




Margin="4"

Width="100"

Height="34"

HorizontalAlignment="Right"

Click="AddButton_Click">

Add Person







The code-behind for the window is as follows:

using System.Windows;

namespace Apress.VisualCSharpRecipes.Chapter17

{

public partial class MainWindow : Window

{

// Create an instance of the PersonCollection class



852



www.it-ebooks.info



CHAPTER 17 ■ WINDOWS PRESENTATION FOUNDATION



PersonCollection people =

new PersonCollection();

public MainWindow()

{

InitializeComponent();

// Set the DataContext to the PersonCollection

this.DataContext = people;

}

private void AddButton_Click(

object sender, RoutedEventArgs e)

{

people.Add(new Person()

{

FirstName = "Simon",

LastName = "Williams",

Age = 39,

Occupation = "Professional"

});

}

}

}

The code for the Person class is omitted for brevity. The code for the PersonCollection class is as

follows:

using System.Collections.ObjectModel;

namespace Apress.VisualCSharpRecipes.Chapter17

{

public class PersonCollection

: ObservableCollection

{

public PersonCollection()

{

this.Add(new Person()

{

FirstName = "Sam",

LastName = "Bourton",

Age = 33,

Occupation = "Engineer"

});

this.Add(new Person()

{

FirstName = "Adam",

LastName = "Freeman",

Age = 37,

Occupation = "Professional"

});



853



www.it-ebooks.info



CHAPTER 17 ■ WINDOWS PRESENTATION FOUNDATION



this.Add(new Person()

{

FirstName = "Sam",

LastName = "Noble",

Age = 24,

Occupation = "Engineer"

});

}

}

}

Figure 17-16 shows the resulting window.



Figure 17-16. Binding to a collection using the master-detail pattern



17-19. Change a Control’s Appearance on Mouseover

Problem

You need to change the appearance of a control when the mouse moves over it.



Solution

Create a System.Windows.Style resource for the System.Windows.Controls.Control, and use a property

trigger to change the properties of the Style when the IsMouseOver property is True.



854



www.it-ebooks.info



CHAPTER 17 ■ WINDOWS PRESENTATION FOUNDATION



How It Works

Every control ultimately inherits from System.Windows.UIElement. This exposes a dependency property

called IsMouseOverProperty. A System.Windows.Trigger can be defined in the Style of the control, which

receives notification when this property changes and can subsequently change the control’s Style.

When the mouse leaves the control, the property is set back to False, which notifies the trigger, and the

control is automatically set back to the default state.



The Code

The following example demonstrates a window with a Style resource and two

System.Windows.Controls.Button controls. The Style uses a Trigger to change the

System.Windows.FontWeight and BitmapEffect properties of the Button controls when the mouse is over

them. The XAML for the window is as follows:


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

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

Title="Recipe17_19" Height="120" Width="240">

















Figure 17-17 shows the resulting window.



855



www.it-ebooks.info



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

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

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

×