Шаблоны элементов управления 1 Логические и визуальные деревья 1
Скачать 2.29 Mb.
страница
1/28
Дата
31.08.2016
Размер
2.29 Mb.
1 2 3 4 5 6 7 8 9 ... 28
Шаблоны элементов управления 1
Логические и визуальные деревья 1
Что собой представляют шаблоны 6
Типы шаблонов 7
Классы Chrome 8
Разбиение элементов управления 9
Создание шаблонов элементов управления 12
Простая кнопка 12
Привязка шаблонов 13
Триггеры шаблонов 15
Организация ресурсов шаблонов 19
Рефакторизация шаблона элемента управления Button 20
Использование шаблонов со стилями 22
Обложки, выбираемые пользователем 26
Создание более сложных шаблонов 29
Шаблоны, состоящие из множества частей 30
Шаблоны элементов управления в ItemsControl 31
Изменение полосы прокрутки 35
Создание специального окна 44
Привязка данных 60
Основы привязки данных 61
Привязка к свойству элемента 61
Ошибки привязки 65
Создание привязки в коде 66
Множественные привязки 67
Направление привязки 72
OneWayToSource 73
Default 76
Обновления привязки 76
Привязка объектов, не являющихся элементами 79
Source 80
RelativeSource 81
DataContext 84
Привязка пользовательских объектов к базе данных 86
Построение компонента доступа к данным 86
Построение объекта данных 92
Отображение привязанного объекта 96
Обновление базы данных 104
Уведомление об изменениях 105
Привязка к коллекции объектов 108
Отображение и редактирование элементов коллекции 109
Привязка к выражению LINQ 114
Преобразование данных 119
Форматирование строк конвертером значений 121
Создание объектов с конвертером значений 127
Применение условного форматирования 131
Оценка множественных свойств 134
Проверка достоверности 136
Проверка достоверности в объекте данных 137
Объекты данных и проверка достоверности 138
ExceptionValidationRule 139
DataErrorValidationRule 141
Специальные правила проверки достоверности 145
Реакция на ошибки проверки достоверности 149
Получение списка исключений 151
Отображение отличающегося индикатора ошибки 153
Шаблоны данных, представления данных, поставщики данных 158
Кратко о привязке данных 159
Шаблоны данных 161
Отделение и многократное использование шаблонов 165
Усовершенствованные шаблоны 168
Варьирование шаблонов 172
Селекторы шаблонов 174
Шаблоны и выбор 178
Селекторы стилей 184
Изменение компоновки элемента 187
Представления данных 187
Извлечение объекта представления 189
Фильтрация коллекций 189
Фильтрация объекта DataTable 193
Сортировка 193
Группирование 195
Создание представлений декларативным образом 200
Навигация в представлении 201
Поставщики данных 205
Объект ObjectDataProvider 206
Обработка ошибок 207
Асинхронная поддержка 207
Поставщик XmlDataProvider 207
Библиографический список 209
Шаблоны элементов управления
В прошлом разработчикам Windows-приложений приходилось делать выбор между удобством и гибкостью элементов управления. Для получения максимального удобства они могли использовать заранее заготовленные элементы управления. Эти элементы управления работали достаточно хорошо, но предлагали очень мало возможностей для настройки и почти всегда имели фиксированный визуальный внешний вид. Иногда некоторые элементы управления позволяли прорисовывать часть элемента управления путем реагирования на обратный вызов. Но базовые элементы управления — кнопки, текстовые поля, кнопки-флажки, окна списков и т.д. — были полностью заблокированы.
В результате разработчикам, которым хотелось, чтобы все выглядело немного более стильно, приходилось создавать специальные элементы управления с нуля. Это создавало проблему, и не только потому, что написание необходимой логики для рисования вручную требовало много времени и усилий, но и потому, что разработчикам специальных элементов управления также нужно было самостоятельно реализовать даже базовые функциональные возможности, например, выделение текста в текстовом поле или обработка нажатия клавиш в кнопке. И даже после создания специальных элементов управления их вставка в существующее приложение предполагала выполнение большого объема редактирования, часто вынуждавшего вносить в код различные изменения.
В WPF проблема с настройкой элементов управления решена благодаря стилям и шаблонам. Успех этих функциональных возможностей заключается в способе реализации элементов управления, который в WPF значительно отличается. В предыдущих технологиях разработки пользовательских интерфейсов, таких как Windows Forms, часто применяемые элементы управления на самом деле не реализовались в коде .NET. Вместо этого классы элементов управления Windows Forms упаковывали базовые элементы из API-интерфейса Win32, которые являются жёстко заданными и неизменными. В WPF, как уже говорилось выше, каждый элемент управления создается в чистом коде .NET. Это дает WPF возможность предоставлять механизмы, позволяющие проникать в эти элементы и настраивать или даже полностью изменять их.
Логические и визуальные деревья
Ранее было уделено достаточно много времени рассмотрению модели содержимого окна — другими словами тому, как можно вставлять элементы внутрь других элементов для создания целого окна.
В качества примера возьмем чрезвычайно простое окно с двумя кнопками, показанное на Рис. .
Рис. Простое окно с тремя элементами
Создается такое окно путем вставки внутрь элемента Window элемента управления StackPanel, размещения в нем двух элементов управления Button и добавления внутри каждого из этих элементов управления Button какого-то содержимого по выбору (в данном случае это две строки текста). Код разметки приведен ниже:
Набор элементов, которые были добавлены, называется логическим деревом и показан на Рис. . Разработчикам WPF-приложений большую часть времени придется проводить именно за созданием таких логических деревьев и написанием необходимого для них кода обработки событий. Фактически все рассмотренные выше функциональные возможности работают через логические деревья.
Однако если есть потребность переделать или настроить элементы, от логического дерева пользы мало. Очевидно, что можно просто взять и заменить весь элемент каким-то другим элементом (например, текущий элемент управления Button можно было бы заменить специальным классом FancyButton), но это требует приложения дополнительных усилий и чревато нарушением интерфейса приложения или его кода. Поэтому WPF предлагает дополнительное визуальное дерево.
Визуальное дерево представляет собой расширенную версию логического дерева. В нем элементы разбиваются на еще более мелкие фрагменты. Другими словами, вместо аккуратно инкапсулированного черного прямоугольника вроде элемента управления Button в нем будут отображаться визуальные компоненты этой кнопки, а именно — граница, придающая кнопкам их отличительный затененный фон (представленная классом ButtonChrome), находящийся внутри контейнер (ContentPresenter) и блок с текстом кнопки (представленный классом TextBlock). Для примера на Рис. показано визуальное дерево для окна на Рис. .
Рис. Логическое дерево окна
Рис. Визуальное дерево окна
Все эти детали сами являются элементами — т.е., каждая отдельная деталь в элементе управления Button представлена классом, который наследуется от FrameworkElement.
Визуальное дерево позволяет разработчикам пользовательских интерфейсов делать две следующих полезных вещи:
Изменять один из элементов в визуальном дереве с помощью стилей. Можно выбирать конкретный подлежащий изменению элемент с помощью свойства Style.TargetType, а можно даже использовать триггеры и делать так, чтобы изменения вносились автоматически при изменении свойств того или иного элемента управления. Однако есть детали, которые очень трудно или вообще невозможно изменять.
Создавать для элемента управления новый шаблон. В таком случае для построения визуального дерева в точности тем образом, которым хочет разработчик, будет использоваться шаблон элемента управления.
Отметим, что WPF предоставляет два класса для работы с логическими и визуальными деревьями, а именно— класс System.Windows.LogicalTreeHelper и класс System.Windows.Media.VisualTreeHelper.
Класс LogicalTreeHelper уже демонстрировался выше, где он позволял подключать обработчики событий в WPF-приложении с не скомпилированным, загружаемым динамически XAML-документом. Он предлагает относительно скудный набор методов, которые перечислены в Таблица . Хотя иногда эти методы и бывают полезными, в большинстве случаев вместо них будут использоваться методы конкретного элемента FrameworkElement.
Таблица Методы класса LogicalTreeHelper
Имя
Описание
FindLogicalNode()
Отыскивает определенный элемент по имени, начиная поиск с указанного элемента и опускаясь далее вниз по логическому дереву.
BringIntoView()
Прокручивает элемент так, чтобы он стал видимым (если он находится в поддерживающем прокручивание контейнере и в текущий момент не виден). Метод FrameworkElement.BringIntoView() делает то же самое.
GetParent()
Извлекает родительский элемент указанного элемента.
GetChildren()
Извлекает дочерний элемент указанного элемента. Как показывалось выше, разные элементы поддерживают разные модели содержимого. Например, панели поддерживают множество дочерних элементов, а элементы управления содержимым — только один дочерний элемент. Однако метод GetChildren() работает с элементами любого типа.
КлассVisualTreeHelper предоставляет несколько похожих методов—GetChildrenCount(), GetChild() и GetParent() — вместе с небольшим набором методов, которые предназначены для выполнения низкоуровневого рисования.
Класс VisualTreeHelper также еще представляет собой интересный способ для изучения визуального дерева в приложении. С помощью его метода GetChild() можно разворачивать визуальное дерево любого окна и отображать его для рассмотрения. Это хорошее средство получения информации, и требует оно всего лишь небольшого фрагмента рекурсивного кода.
На Рис. показана одна из возможных реализаций, предполагающая отображение всего визуального дерева в отдельном окне, начиная с любого предоставленного объекта. В данном примере еще одно окно используется окном для отображения своего визуального дерева.
Рис. Представление визуального дерева
Здесь окно с именем Window1 содержит элемент Border, который, в свою очередь, содержит AdornerDecorator. Класс AdornerDecorator обеспечивает поддержку для прорисовки содержимого в декоративном слое, который представляет собой невидимую область, накладываемую поверх содержимого элемента. WPF использует этот слой для прорисовки деталей вроде меток фокусировки и индикаторов перетаскивания. Внутри AdornetDecorator находится ContentPresenter. который вмещает содержимое окна. Это содержимое включает StackPanel с двумя элементами управления Button, каждый из которых состоит из класса ButtonChrome (который прорисовывает стандартный внешний вид кнопки) и класса ContentPresenter (хранящего содержимое кнопки). И, наконец, внутри класса ContentPresenter каждой кнопки находится класс TextBlock, который упаковывает текст, видимый в окне.
Ниже приведен весь код для окна VisualTreeDisplay.
public partial class VisualTreeDisplay : System.Windows.Window
{
public VisualTreeDisplay()
{
InitializeComponent();
}
public void ShowVisualTree(DependencyObject element)
{
// Clear the tree.
treeElements.Items.Clear();
// Start processing elements, begin at the root.
После добавления этого дерева в проект данный код можно будет использовать и из любого другого окна для отображения его визуального дерева:
Проникать в визуальное дерево других приложений можно с помощью утилиты Snoop, которая является частью Expression Blend и доступна отдельно по адресу http://www.blois.us/Snoop/. Эта утилита позволяет изучать визуальное дерево любого WPF-приложения, которое выполняется в текущий момент, а также увеличивать масштаб на любом элементе, наблюдать за маршрутизируемыми событиями по мере их возникновения и изучать и даже изменять свойства элементов.