Шаблоны
87WPF --- Шаблоны и пользовательские элементы управления WPF --- Шаблоны
Просмотр визуального дерева вызывает несколько интересных вопросов. Например, как элемент управления транслируется из логического дерева в расширенное представление визуального дерева?
Оказывается, каждый элемент управления имеет встроенное средство, определяющее способ его визуализации (как группу более фундаментальных элементов). Это средство называется шаблоном элемента управления (control template) и определяется с помощью блока XAML-разметки.
Каждый элемент управления WPF спроектирован как не имеющий внешнего вида, в том смысле, что его внешний вид может быть полностью переопределен. Неизменным остается лишь поведение элемента управления, которое жестко привязано к классу элемента (хотя часто оно может быть тонко настроено с помощью свойств).
Когда принято решение воспользоваться элементом управления Button, это объясняется тем, что нужно поведение, подобное кнопке (другими словами, элемент, представляющий содержимое, на котором можно щелкнуть для активизации действия, и который может служить кнопкой по умолчанию или кнопкой отмены в окне). Однако можно практически произвольно изменять внешний вид кнопки и ее реакцию на наведение курсора и нажатие кнопок мыши, как и любой другой аспект внешности и визуального поведения.
Ниже приведена упрощенная версия шаблона для популярного класса Button. В ней отсутствует объявление пространства имен XML, атрибуты, устанавливающие свойства вложенных элементов, и триггеры, определяющие поведение кнопки, когда она недоступна, имеет фокус или на ней совершен щелчок:
<ControlTemplate ... >
<mwt:ButtonChrome Name="Chrome" ... >
<ContentPresenter Content="{TemplateBinding ContentControl.Content}" ... />
</mwt:ButtonChrome>
<ControlTemplate.Triggers>
...
</ControlTemplate.Triggers>
</ControlTemplate>
Хотя пока еще не рассматривались классы ButtonChrome и ContentPresenter, можно легко понять, что шаблон элемента управления предоставляет расширение, которое вы видели в визуальном дереве. Класс ButtonChrome определяет стандартные визуальные элементы кнопки, в то время как ContentPresenter хранит все содержимое. Для построения совершенно новой кнопки понадобится лишь создать новый шаблон элемента управления. Вместо ButtonChrome можно было бы использовать что-то другое, возможно, собственный специальный элемент или элемент, рисующий фигуру.
Класс ButtonChrome унаследован от Decorator (как и класс Border). Это значит, что он спроектирован специально для того, чтобы создавать графическое оформление вокруг другого элемента, в данном случае — вокруг содержимого кнопки.
Триггеры управляют изменениями кнопки при получении ею фокуса, при щелчке на ней и при запрете к ней доступа. В этих триггерах нет ничего особенно интересного. Вместо выполнения всей рутинной работы самостоятельно, триггеры фокуса и щелчка просто модифицируют свойства класса ButtonChrome, которые определяют внешний вид кнопки.
Типы шаблонов
Внимание в этом разделе сосредоточено на шаблонах элементов управления, которые позволяют определять элементы, составляющие элемент управления. Однако на самом деле в мире WPF существует три типа шаблонов, и все они наследуются от базового класса FrameworkTemplate.
Наряду с шаблонами элементов управления (представленными классом ControlTemplate) есть шаблоны данных (классы DataTemplate и HierarchicalDataTemplate), а также более специализированный шаблон панели для ItemsControl(ItemsPanelTemplate).
Шаблоны данных используются для извлечения данных из объекта и отображения их в элементе управления содержимым либо в индивидуальных позициях списочного элемента. Шаблоны данных незаменимы в сценариях привязки данных. В некоторой степени шаблоны данных и шаблоны элементов управления пересекаются. Например, оба типа шаблонов позволяют вставлять дополнительные элементы, применять форматирование и т.д. Однако шаблоны данных служат для добавления элементов внутрь существующего элемента управления.
Предварительно определенные аспекты этого элемента управления при этом не изменяются. С другой стороны, шаблоны элементов управления открывают более широкие возможности, позволяя полностью переписать модель содержимого элемента управления.
Наконец, шаблоны панелей применяются для управления компоновкой позиций в списочном элементе управления (элементов, унаследованных от класса ItemsControl). Например, их можно использовать для создания окон списков, которые располагают свои элементы слева направо и затем сверху вниз (вместо стандартного размещения сверху вниз в один столбец).
В пределах одного элемента управления определенно можно комбинировать разные типы шаблонов. Например, для создания блестящего окна списка, привязанного к определенному типу данных, расположения его элементов нестандартным образом и замены обычной рамки чем-то более выразительным, понадобится создать собственные шаблоны данных, шаблон панели и шаблон элемента управления.
Классы Chrome
Класс ButtonChrome определен в пространстве имен Microsoft.Windows.Themes, которое содержит относительно небольшой набор сходных классов, визуализирующих базовые детали Windows. Наряду с ButtonChrome он включает BulletChrome (для флажков и переключателей), ScrollChrome (для полос прокрутки), ListBoxChrome и SystemDropShadowChrome. Это наиболее низкий уровень общедоступного API-интерфейса элементов управления.
На чуть более высоком уровне находится пространство имен System.Windows.Controls.Primitives, содержащее множество базовых элементов, которые можно использовать независимо, но гораздо чаще помещать в оболочки более удобных элементов управления. К ним относятся ScrollBar, ResizeGrip (для изменения размеров окна), Thumb (перетаскиваемая кнопка на полосе прокрутки), TickBar (дополнительный набор засечек на ползунке) и т.д. По сути, System.Windows.Controls.Primitives представляет готовые ингредиенты, которые можно применять в самых разных элементах управления, и которые не слишком полезны сами по себе, в то время как Microsoft.Windows.Themes содержит низкоуровневую логику рисования для визуализации этих деталей.
Имеется еще одно отличие. Типы в System.Windows.Controls.Primitives, как и большинство типов WPF, определены в сборке PresentationFramework.dll. Однако типы, находящиеся в Microsoft.Windows.Themes, определены отдельно, в трех разных сборках: PresentationFramework.Aero.dll, PresentationFramework.Luna.dll и PresentationFramework.Royale.dll. Каждая из сборок включает собственную версию класса ButtonChrome (и других классов Chrome), со слегка отличающейся логикой визуализации. Версия, которую использует WPF, зависит от операционной системы и настроек темы.
Хотя шаблоны элементов управления часто рисуют в классах Chrome, они не всегда должны делать это. Например, элемент ResizeGrip (который создает сетку точек в нижнем правом углу окна с изменяемым размером) достаточно прост, чтобы его шаблон мог использовать классы рисования - DrawingBrush и LinearGradientBrush.