Опубликован: 13.12.2011 | Доступ: свободный | Студентов: 1021 / 34 | Оценка: 4.29 / 4.57 | Длительность: 13:56:00
Лекция 3:

Стили и шаблоны элементов управления WPF

Установка шаблонов через стили

Связывание в шаблонах не ограничивается классом ContentPresenter. На самом деле вы можете использовать его в любом месте шаблона Control’а. Давайте рассмотрим наш пример кнопки с "вшитым" красным цветом фона элемента Border. Вот как можно использовать шаблонное связывание для управления фоном:

<Border BorderBrush="Orange" 
        BorderThickness="3" 
        CornerRadius="10"
        Background="{TemplateBinding Background}">

Этот пример затрагивает один из вечных вопросов проектирования. Стоит ли жестко "зашивать" цвет, чтобы иметь стандартный вид кнопок, или применить связывание, чтобы сделать шаблон более гибким? На этот раз у нас имеется отличный компромисс, позволяющий убить сразу двух зайцев: вы можете сочетать шаблоны и стили! Основная идея в том, чтобы шаблон позволял изменять цвет фона, а стиль содержал бы значения по умолчанию, на случай, если цвет не будет указан явно:

<Style x:Key="ButtonStyle" TargetType="Button">
    <Setter Property="Background" Value="Red"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="Button">
                <Border BorderBrush="Orange" 
                        BorderThickness="3" 
                        CornerRadius="10"
                        Background="{TemplateBinding Background}">
                    <ContentPresenter Margin="{TemplateBinding Padding}"/>
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

Но можно оставить стиль отдельным ресурсом:

<Style x:Key="ButtonStyle" TargetType="Button">
    <Setter Property="Background" Value="Red"/>
    <Setter Property="Template" Value="{StaticResource ButtonTemplate}"/>
</Style>

Только учтите, что в таком случае объявление стиля должно следовать после объявления шаблона.

Синхронное использование стилей и шаблонов также бывает полезным, если вам нужно задать свойства (зависимые свойства), отсутствующие в ContentPresenter или в элементах контейнера вашего шаблона. Обратите внимание, что в нашем примере нет связывания для цвета шрифта кнопки. А все потому, что эти свойства (Foreground, FontFamily, FontSize, FontWeight, и т.д.) участвуют в наследовании свойств. Когда вы задаете эти значения в элементе более высокого уровня (например, в кнопке), они распространяются на вложенные элементы (например, TextBlock внутри кнопки). Сам же ContentPresenter не имеет этих свойств, и в этом нет необходимости. Значения этих свойств передаются от Control’а к вложенному контенту минуя ContentPresenter.

Иногда вам может понадобиться изменить значение наследуемого свойства, чтобы ограничить изменение вида вашего Control’а. Например, в нашем случае важно, чтобы цвет текста был белым, поскольку белый текст лучше выделяется на красном фоне кнопки. Но стандартный цвет шрифта наследуется от Silverlight страницы, на которой расположены наши элементы, и этот цвет – черный. К тому же вы не можете установить цвет через ContentPresenter, т.к. он не содержит свойства Foreground. Для решения этой проблемы нужно объединить шаблон Control’а со стилем, сеттер которого задает белый цвет текста:

<Style x:Key="ButtonStyle" TargetType="Button">
    <Setter Property="Foreground" Value="White"/>
    <Setter Property="Background" Value="Red"/>
    <Setter Property="Template" Value="{StaticResource ButtonTemplate}"/>
</Style>

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

Повторное использование настроек цвета

Как вы уже знаете, гибкий шаблон Control’а можно настраивать через свойства Control’а, значение которых можно задавать в стиле. Однако Silverlight приложения редко изменяют свойства только одного Control’а за раз. Как правило, для изменения вида приложения изменяются настройки сразу у множества шаблонов. В таких ситуациях нужно уметь синхронно использовать определенные свойства Control’ов (например, настройки цвета). Для этого все "вшитые" значения вынесите из стилей и шаблонов, описав их как отдельные ресурсы. Например:

<SolidColorBrush x:Key="BackgroundBrush" Color="Red"/>

Затем вы можете обращаться к этим ресурсам из стилей и шаблонов:

<Style x:Key="ButtonStyle" TargetType="Button">
    <Setter Property="Foreground" Value="White"/>
    <Setter Property="Background" Value="{StaticResource BackgroundBrush}"/>
    <Setter Property="Template" Value="{StaticResource ButtonTemplate}"/>
</Style>

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

Для большей гибкости вы можете вынести в отдельный ресурс даже настройки цветов, а затем использовать их как ресурсы кисти:

<Color
   x:Key="BackgroundColor">#FF800000</Color>
<SolidColorBrush
   x:Key="BackgroundBrush" Color="{StaticResource BackgroundColor}"/>

Такой принцип позволяет повторно использовать цветовую схему для самых разных случаев (например, для заливки и для градиентной кисти) без необходимости дублировать информацию о цвете в вашей разметке. При правильном использовании такой модели вы сможете изменять цветовую схему всего приложения, манипулируя всего лишь одним набором ресурсов.

Замечание: при объявлении цвета как отдельного ресурса ему может быть задан цвет в виде имени цвета или в виде шестнадцатеричного HTML-кода цвета (как в примере). Но, к сожалению, нельзя объявить цвет в XAML, используя набор красного, зеленого, и синего составляющих цвета.

Ключевые термины

Styles: совокупность значений свойств, которые можно все сразу применить к нужному элементу.

Templates: каждый Control содержит встроенный набор правил, определяющий его отрисовку (в виде набора более простых элементов). Этот набор правил называется шаблоном Control’а (control template). Описывается он как блок XAML-разметки и применяется к Control’у через свойство "Template".

Краткие итоги

В этой лекции мы рассмотрели механизм применения некоторого набора свойств к одному или нескольким элементам управления - стили. С помощью стилей можно создавать однородные темы и применять их к разным приложениям. Однако у стилей имеются ограничения на изменение свойств, описанных в классе элемента. В Silverlight имеется куда более радикальный инструмент для настройки подобных вещей, называемый шаблонами (templates). Тогда как стили можно применять к любому Silverlight элементу, использование шаблонов ограничено Silverlight Control’ами, т.е. элементами, которые наследуются от класса Control, принадлежащего пространству имен System.Windows.Controls. Более детально эти отличия мы рассмотрим в следующей лекции.

Набор для практики

Вопросы:

  1. Приведите пример необходимости использования класса ContentPresenter.
  2. Назначение ресурсов в WPF. Пример использования?
  3. Назначение стилей в WPF. Пример использования?
  4. Назначение шаблонов в WPF. Пример использования?
  5. Поясните назначение установки шаблонов через стили.