Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Windows Presentation Foundation.docx
Скачиваний:
12
Добавлен:
13.08.2019
Размер:
1.13 Mб
Скачать

15. ПрИвязкакколлекциямиШаблоныданных

Рассмотрим следующий пример. Пусть имеется класс, описывающий задание для программиста, и классс набором заданий:

publicclassTask

{

publicstring Name { get; set; }

publicstring Note { get; set; }

publicint Priority { get; set; }

publicTaskType Type { get; set; }

}

publicenumTaskType { Coding, Testing, Support }

publicclassTasks : List<Task>

{

public Tasks()

{

Add(newTask{ Name = "Data loading",

Note = "Need to test work with DB",

Priority = 2, Type = TaskType.Testing });

Add(newTask{ Name = "Log class",

Note = "Finish this work",

Priority = 2, Type = TaskType.Coding });

Add(newTask{ Name = "IoC Usage",

Note = "Find more info",

Priority = 4, Type = TaskType.Coding });

Add(newTask{ Name = "Urgent bug fixing",

Note = "Problem with class C",

Priority = 1, Type = TaskType.Support });

Add(newTask{ Name = "UI development",

Note = "Make markup for Main Window",

Priority = 1, Type = TaskType.Coding });

Add(newTask{ Name = "Help Doc",

Note = "Write technical documentation",

Priority = 3, Type = TaskType.Support });

Add(newTask{ Name = "New project!",

Note = "Plan the meeting",

Priority = 1, Type = TaskType.Support });

}

}

Необходимо создать приложение WPF, отображающее задания. Список заданий будет показан в элементе ListBox, связанном с объектом классаTasks. Класс ItemsControl, являющийся предком всех списковых элементов управления, определяет два свойства, которые будут использоваться при привязке:

  • ItemsSource– указывает на коллекцию, содержащую все объекты, которые будут показаны в списке. В свойство ItemsSource можно поместить любой объект, реализующий интерфейс IEnumerable или его универсальную версию.

  • DisplayMemberPath–путь к свойству, которое будет применяться для создания отображаемого текста каждого элемента коллекции.

Детальная информация о выбранном задании будет отображаться в наборе текстовых полей. Для этого применяется привязка к свойству DataContext контейнера, обрамляющего поля.

<Window x:Class="TaskView.MainWindow" Title="List of Tasks"

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

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

<StackPanel Margin="5" Orientation="Horizontal">

<ListBox Name="lstTasks" DisplayMemberPath="Name"Width="250"/>

<Grid Margin="5" DataContext="{Binding ElementName=lstTasks,

Path=SelectedItem}">

<Grid.ColumnDefinitions>

<ColumnDefinition Width="Auto" />

<ColumnDefinition Width="7" />

<ColumnDefinition Width="200" />

</Grid.ColumnDefinitions>

<Grid.RowDefinitions>

<RowDefinition Height="Auto" />

<RowDefinition Height="11" />

<RowDefinition Height="Auto" />

<RowDefinition Height="11" />

<RowDefinition Height="Auto" />

</Grid.RowDefinitions>

<TextBlock Grid.Row="0" Grid.Column="0" Text="Name:" />

<TextBox Grid.Row="0" Grid.Column="2"

Text="{Binding Name}" />

<TextBlock Grid.Row="2" Grid.Column="0" Text="Note:" />

<TextBox Grid.Row="2" Grid.Column="2"

Text="{Binding Note}" />

<TextBlock Grid.Row="4" Grid.Column="0" Text="Priority:" />

<TextBox Grid.Row="4" Grid.Column="2"

Text="{Binding Priority}" />

</Grid>

</StackPanel>

</Window>

// файлCode Behind

namespace TaskView

{

publicpartialclassMainWindow : Window

{

public MainWindow()

{

InitializeComponent();

lstTasks.ItemsSource = newTasks();

}

}

}

Рис. 39.Привязка списку, форма «главная-подробности».

Поддержка, которую даёт интерфейс IEnumerable, ограничена привязкой только для чтения – изменения, производимые в коллекции после привязки, в списковом элементе управления не отображаются. Чтобы включить отслеживание изменений, нужно использовать коллекцию с интерфейсом INotifyCollectionChanged. WPF включает единственную коллекцию, реализующую этот интерфейс, – это класс ObservableCollection<T>.

// изменённыйклассMainWindow

publicpartialclassMainWindow : Window

{

privatereadonlyObservableCollection<Task> tasks;

public MainWindow()

{

InitializeComponent();

tasks = newObservableCollection<Task>(newTasks());

lstTasks.ItemsSource = tasks;

}

}

Изменим внешний вид списка заданий при помощи шаблона данных. Шаблоны данных (datatemplates) – механизм для настройки отображенияобъектов определённого типа. В WPFшаблон данных – это объект класса System.Windows.DataTemplate. Основное свойство шаблона –VisualTree. Оно содержит визуальный элемент, определяющий внешний вид шаблона. Часто этим визуальным элементом является контейнер компоновки. В разметке XAMLдля задания VisualTree достаточно поместить в DataTemplate дочерний элемент. При формировании VisualTree обычно используется привязка данных для извлечения информации из объекта, для которого применяется шаблон. Сам шаблон данных, как правило, размещают в ресурсах окна или приложения.

С учётом вышесказанного определим шаблон данных в ресурсах окна и используем свойство списка ItemTemplateдля применения шаблона к каждому элементу списка:

<!-- определяем шаблон в ресурсах окна -->

<Window.Resources>

<DataTemplate x:Key="taskTemplate">

<Border Name="border" BorderBrush="Aqua" BorderThickness="1"

CornerRadius="2" Padding="5" Margin="5">

<TextBlock FontSize="14" FontWeight="Bold"

Text="{Binding Name}" />

</Border>

</DataTemplate>

</Window.Resources>

<!-- изменённаянастройка ListBox -->

<ListBox Name="lstTasks" HorizontalContentAlignment="Stretch"

ItemTemplate="{StaticResource taskTemplate}" Width="250"/>

Рис. 40.Список, к которому применён шаблон данных.

У классаDataTemplate имеется свойство DataType, определяющее тип данных, к которому будет применяться шаблон. Если задано это свойство, WPFбудет использовать шаблон в любой ситуации, где до этого выводилась строка с результатом ToString():

<!-- не указываем ключ ресурса, если шаблон в ресурсах -->

<!--подключено xmlns:TaskView="clr-namespace:TaskView" -->

<DataTemplate DataType="{x:Type TaskView:Task}">

<!-- описание шаблона не изменилось -->

</DataTemplate>

<!-- вListBoxнезадаём свойствоItemTemplate -->

<ListBox Name="lstTasks" Width="250" HorizontalContentAlignment="Stretch"/>

В шаблон данных можно поместить триггеры данных. Следующий пример показывает использование триггера для того, чтобы изменить цвет окантовки задач из группы TaskType.Support:

<!-- эта разметка – часть шаблона DataTemplate -->

<DataTemplate.Triggers>

<DataTrigger Binding="{Binding Path=Type}" Value="Support">

<Setter TargetName="border" Property="BorderBrush"

Value="Brown" />

</DataTrigger>

</DataTemplate.Triggers>

Обратитевнимание–элемент<Setter>содержитустановкуTargetName. Как ясно из контекста,TargetName используется, чтобы обратиться к именованному дочернему элементу визуального представления шаблона данных. Дочерний элемент должен быть описан до триггера.

В WPFсписковые элементыуправления поддерживают возможность выбора для объекта одного из нескольких шаблонов данных. Предположим, что в примере со списком заданий требуется особым образом отображать задания с приоритетом, равным 1. Определим в ресурсах окна ещё один шаблон данных:

<DataTemplate x:Key="importantTask">

<Border BorderBrush="Red" BorderThickness="2"CornerRadius="2"

Padding="5" Margin="5">

<TextBlock FontSize="18" Foreground="Red" Text="{Binding Name}"/>

</Border>

</DataTemplate>

Выбор шаблона выполняется программно, с помощью создания подкласса для DataTemplateSelector и переопределения метода SelectTemplate():

publicclassTaskTemplateSelector : DataTemplateSelector

{

publicoverrideDataTemplate SelectTemplate(object item,

DependencyObject container)

{

if (item != null&& item isTask)

{

var task = item asTask;

Window window = Application.Current.MainWindow;

return task.Priority == 1?

window.FindResource("importantTask")asDataTemplate :

window.FindResource(newDataTemplateKey(typeof(Task)))

asDataTemplate;

}

returnnull;

}

}

ЗатемможнообъявитьобъектTaskTemplateSelectorвкачествересурсаиназначитьэтотресурссвойствуListBox.ItemTemplateSelector. ОбъектListBoxвызываетметодSelectTemplate()длякаждогоэлементавбазовойколлекции.

<ListBoxName="lstTasks" Width="250"

HorizontalContentAlignment="Stretch"

ItemTemplateSelector="{StaticResource selector}"/>

Рис. 41.Селектор шаблонов в действии.

При работе с иерархическими элементами управления (например, TreeView) вместо шаблона данных на основе DataTemplate следует использовать HiererchicalDataTemplate.У такого шаблона имеется свойство ItemsSource, которое нужно связать с дочерней коллекцией, и свойство ItemTemplate – дочернийшаблон данных (DataTemplate или HiererchicalDataTemplate).