Главная » WPF » Модели, отображение и стили

0

Наличие перекрытия между Style и ControlTemplate подводит нас к вопросу о разделении  отображения и поведения.  В объектно  ориентированном проектиро вании есть несколько  хорошо известных  паттернов, один из которых называется

«модель  вид контроллер» (MVC). В нем объекты распределяются по трем кате гориям:  (1)  модель,  определяющая структуры  данных; (2)  вид, определяющий отображение  данных, и (3) контроллер, описывающий взаимодействие между моделью и видом. Хотя WPF,  строго говоря, не придерживается этого паттерна, полезно вспомнить  о нем при рассмотрении стилей и шаблонов.

В классах элементов  управления WPF,  например  Button, определена  как мо дель данных, так и модель взаимодействия элемента.  Отображение же элемента целиком описывается шаблоном. Кроме того, WPF позволяет  передать данные с помощью модели содержимого,  которая  была рассмотрена  в главе 3. При нали чии модели содержимого  мы получаем суть паттерна MVC без обычной для него сложности.

Поразмышлять о таком  разделении  данных  (модели), шаблона  (вида)  и уп равления (контроллера) любопытно, потому что стили дают простой способ свя зать их воедино. Элементы  управления настраиваются с помощью свойств, уста новку  которых  поддерживают стили.  Шаблоны  обеспечивают  настройку  путем привязок свойств и ресурсов, которые также устанавливаются в стилях. А данные передаются  элементам  управления через свойства  последних, и это тоже описы вается стилями.  Стало быть, стили не только участвуют в настройке  каждого из трех компонентов,  но и объединяют  их; с помощью стиля  мы можем ассоцииро вать с элементом управления шаблон и источник данных.

Теперь можно более внимательно присмотреться к взаимосвязи между стиля

ми и шаблонами.  Начнем с простого шаблона кнопки:

<ControlTemplate x:Key=’simpleButtonTemplate’ TargetType=’{x:Type Button}’>

<Border>

<ContentPresenter

HorizontalAlignment=’Center’

VerticalAlignment=’Center’ />

</Border>

</ControlTemplate>

На первый  взгляд  не очевидно, что этот шаблон поддерживает какую то до полнительную настройку;  в нем нет ссылок  на свойства  элемента.  В главе 3 мы видели что объект ContentPresenter неявно привязан к свойству Content шаблон ного элемента. Поэтому мы могли бы установить  свойство Content и шаблон эле мента управления и посмотреть, что получится.

С помощью TemplateBinding мы можем привязать и другие свойства к шабло

ну, о чем шла речь в главе 7:

<ControlTemplate x:Key=’simpleButtonTemplate’ TargetType=’{x:Type Button}’>

<Border

Background=’{TemplateBinding Property=Background}’>

<ContentPresenter HorizontalAlignment=’Center’ VerticalAlignment=’Center’ />

</Border>

</ControlTemplate>

Теперь в шаблоне для кнопки есть параметр, который является свойством са мой кнопки, поэтому мы можем стилизовать кнопку с помощью свойства Background и тем самым заставить стиль повлиять на отображение:

<Button Template=’{DynamicResource simpleButtonTemplate}’>

<Button.Style>

<Style TargetType=’{x:Type Button}’>

<Setter Property=’Background’ Value=’Red’ />

</Style>

</Button.Style> Hello, Red World!

</Button>

Такой подход позволяет создать несколько более гибкий шаблон, но наши возможности ограничены  настройкой  только тех свойств, для которых это было предусмотрено автором элемента (например, Background и Foreground). Если же хочется большего, например  задать в шаблоне цвет «подсвеченной» кнопки, то у нас есть три варианта:  (1)  создать новый элемент  с дополнительным свойством; (2)  создать присоединенное свойство, применимое к настраиваемому элементу; (3) использовать ресурс с заранее известным  именем.

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

случае они более приспособлены для изменения поведения, тогда как именован

ные ресурсы естественно  работают в стилях.

Для определения именованного ресурса нам понадобится уникальный ключ, ко

торый мы получим, создав статический экземпляр класса ComponentResourceKey2:

public static class SimpleButton {

public static readonly ComponentResourceKey RingBrush =

new ComponentResourceKey(typeof(SimpleButton), «RingBrush»);

}

Теперь у нас есть есть глобально уникальный идентификатор нового свойства, который  мы можем использовать в шаблоне. В приведенной ниже разметке  мы связываем свойство Border.BorderBrush с именованным ресурсом:

<ControlTemplate x:Key=’simpleButtonTemplate’ TargetType=’{x:Type Button}’>

<Border

BorderBrush=

‘{DynamicResource {x:Static l:SimpleButton.RingBrush}}’ BorderThickness=’5’

Background=’{TemplateBinding Property=Background}’>

<ContentPresenter HorizontalAlignment=’Center’ VerticalAlignment=’Center’ />

</Border>

</ControlTemplate>

В стиле для элемента  Button мы теперь можем настроить  этот ресурс, равно как и любые локальные свойства:

<Button Template=’{DynamicResource simpleButtonTemplate}’>

<Button.Style>

<Style TargetType=’{x:Type Button}’>

<Style.Resources>

<SolidColorBrush

x:Key=’{x:Static l:SimpleButton.RingBrush}’ Color=’Red’ />

</Style.Resources>

<Setter Property=’Background’ Value=’Red’ />

</Style>

</Button.Style> Hello, World!

</Button>

2  Класс ComponentResourceKey здесь не обязателен, но он дает удобный способ создать гло% бально уникальное значение. Комбинация типа и строки определяет уникальное пространство имен (строгий именованный тип CLR) и домен имен (строка). Единственное требование сос% тоит в том, чтобы ключ был уникален и корректно реализовывал методы GetHashCode и Equals.

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

<Button>

<Button.Style>

<Style TargetType=’{x:Type Button}’>

<Style.Resources>

<SolidColorBrush

x:Key=’{x:Static l:SimpleButton.RingBrush}’ Color=’Red’ />

</Style.Resources>

<Setter Property=’Background’ Value=’Red’ />

<Setter Property=’Template’

Value=’{DynamicResource simpleButtonTemplate}’ />

</Style>

</Button.Style> Hello, World!

</Button>

Если задуматься  обо всем вместе – шаблонах, стилях и ресурсах, то мы прихо дим к выводу, что возможен  интересный способ упаковки,  который целиком оп ределяет внешний облик элемента управления. Он называется темой.

Источник: К. Андерсон  Основы  Windows Presentation Foundation. Пер. с англ. А. Слинкина — М.: ДМК Пресс, 2008 — 432 с.: ил.

По теме:

  • Комментарии