Шаблоны

87

Просмотр визуального дерева вызывает несколько интересных вопросов. Например, как элемент управления транслируется из логического дерева в расширенное представление визуального дерева?

Оказывается, каждый элемент управления имеет встроенное средство, определяющее способ его визуализации (как группу более фундаментальных элементов). Это средство называется шаблоном элемента управления (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.

Пройди тесты
Лучший чат для C# программистов