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

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

Аннотация: Очень часто при разработке графического интерфейса пользователя на WPF программист сталкивается с необходимостью создать элемент управления, который бы отличался по виду и/или набору возможностей от уже имеющихся в Microsoft .NET Framework. Видя разнообразные сложные элементы управления, хочется сразу приступить к работе, создать свой User Control и таким образом решить задачу. Правильный ли это подход, мы будем разбираться в этой лекции.

Цель лекции: получить знания о стилях и шаблонах. Научить создавать и повторно использовать шаблон Control’а. Задавать шаблон через стиль.

В Windows Presentation Foundation существует очень четкое разделение между поведением Control'а и тем, как он выглядит. К примеру, поведение объекта класса Button состоит в том, чтобы реагировать на различные события по клику, но его вид может быть любым — вы можете сделать кнопку в виде стрелки, рыбы, или чего-либо еще, что подходит для вашего приложения. Переопределение отображения Control'а очень просто сделать стилями и шаблонами. В WPF стилизация и использование шаблонов относятся к набору функций (стилей, шаблонов, триггеров и раскадровок), позволяющих разработчикам и дизайнерам создавать визуально привлекательные эффекты, а также создавать целостный внешний вид своих продуктов. Несмотря на то, что разработчики и дизайнеры могут настроить внешний вид в масштабе приложений, для обслуживания и синхронного использования внешнего вида внутри приложений и между приложениями необходима строгая модель стилей и шаблонов. WPF предоставляет такую модель.

Другая функция модели стилизации WPF состоит в разделении представления и логики. Это означает, что дизайнеры могут создавать внешний вид приложения, используя только XAML, в то же самое время, когда разработчики работают над логикой программы, используя C# или Visual Basic.

Стили

Стиль – это совокупность значений свойств, которые можно все сразу применить к нужному элементу. В Silverlight стили позволяют разгрузить вашу XAML разметку путем вынесения деталей форматирования элемента в отдельный блок. Система Silverlight стилей играет ту же роль, что и стандарт каскадных таблиц стилей (CSS) в HTML-верстке. Как и CSS, стили в Silverlight позволяют вам определять базовый набор характеристик форматирования и использовать их в вашем приложении для обеспечения согласованности. Но есть и несколько важных ограничений. Например, вы не сможете применить один стиль к элементам разных типов или назначить автоматическое использование стиля. По этой причине стили кажутся несколько неудобными, хотя и являются одной из ключевых возможностей.

Создание стиля

Представьте, что вам нужно стандартизировать шрифт и его цвет для всех кнопок страницы. Первым делом опишите объект Style, содержащий в себе все необходимые вам свойства. Поместите этот объект как ресурс (например, в секции UserControl.Resources, в которой можно хранить ресурсы, относящиеся к данной странице):

<UserControl.Resources>
    <Style x:Key="BigButtonStyle" TargetType="Button">
        ...
    </Style>
</UserControl.Resources>

У стиля, как и у всех ресурсов, имеется имя-ключ, по которому вы можете к нему обращаться. В нашем примере имя ключа – BigButtonStyle. (Обычно принято добавлять к именам стилей окончание "Style"). Кроме того, для любого Silverlight стиля должно быть задано поле TargetType, определяющее тип элементов, к которым может применяться данный стиль. В нашем случае стиль создается для форматирования кнопок (Button).

Наш объект Style содержит коллекцию сеттеров (setter) состоящую из 6-ти Setter-объектов (по одному на каждое свойство). Каждый сеттер описывает только одно свойство элемента. Единственным ограничением является то, что сеттер способен изменять только зависимые свойства (dependency properties), и никакие другие. Но, как показывает практика, это не такое уж и большое ограничение, поскольку почти все свойства Silverlight элементов – зависимые свойства. Сеттеры свойств могут влиять на любые зависимые свойства, даже на те, что управляют поведением объекта, а не его внешним видом. К примеру, если вы применяете стиль к текстовому полю, можете выставлять параметры AcceptsReturn и IsReadOnly непосредственно в самом стиле.

Перед вами стиль большой кнопки с белым текстом шрифта Georgia на темном фоне:

<UserControl.Resources>
    <Style x:Key="BigButtonStyle" TargetType="Button">
        <Setter Property="FontFamily" Value="Georgia" />
        <Setter Property="FontSize" Value="40" />
        <Setter Property="Foreground" Value="SlateGray" />
        <Setter Property="Background" Value="Black" />
        <Setter Property="Padding" Value="20" />
        <Setter Property="Margin" Value="10" />
    </Style>
</UserControl.Resources>

В некоторых случаях вы не сможете задать значение свойства, используя простой формат записи атрибута. Например, простая запись не позволяет создавать неоднородную кисть LinearGradientBursh или ImageBrush. В такой ситуации вы можете применить уже знакомый для XAML прием замещения атрибута каким-либо вложенным элементом. Вот пример:

<Style x:Key="BigButtonStyle" TargetType="Button">
    <Setter Property="Background">
        <Setter.Value>
            <LinearGradientBrush StartPoint="0,0" EndPoint="1,0">
                <GradientStop Color="Blue"></GradientStop>
                <GradientStop Color="Yellow" Offset="1"></GradientStop>
            </LinearGradientBrush>
        </Setter.Value>
    </Setter>
    ...
</Style>

Использование стиля

Каждому элементу Silverlight можно задать только один стиль (или ни одного). Стиль встраивается в элемент через свойство стиля элемента (которое определено в базовом классе FrameworkElement). Например, чтобы применить к кнопке заранее созданный стиль, вы должны указать ресурс стиля, как в этом случае:

<Button
    Style="{StaticResource BigButtonStyle}"
    Content="A Customized Button"/>

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

На рис. 4.1 показана страница с двумя кнопками, использующими стиль BigButtonStyle.

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

Рис. 4.1. Повторное использование настроек с применением стиля

Система стилей имеет много плюсов. Она не только позволяет вам создавать группы настроек с четкими связями, но и делает вашу XAML разметку более компактной благодаря простому способу подключения этих настроек. Но самое главное, вы можете применять стили, не заботясь об их внутреннем содержимом. В предыдущем примере настройки шрифта были описаны внутри стиля BigButtonSyle. Если спустя какое-то время вы решите увеличить величину значений свойств Padding и Margin, вы сможете просто добавить к описанию стиля соответствующие сеттеры свойств. Тогда новые настройки стиля автоматически вступят в силу для всех кнопок, использующих этот стиль.

Замечание. Технически допустимо задавать стиль программно. Тем не менее, это действие может быть выполнено только один раз. Если вы попытаетесь задать стиль кнопке, которая уже его получила, получите исключение.

Размещение стилей

В предыдущем примере стиль описан на уровне определенной страницы и затем использован для двух кнопок той же страницы. Хотя такая практика наиболее распространена, этот вариант размещения стиля не единственно возможный.

Собственно говоря, вы не обязаны объединять стили с ресурсами. Вы можете, к примеру, определить стиль отдельной кнопки, описав набор атрибутов стиля прямо в самой кнопке, как показано здесь:

<Button Content="A Customized Button">
    <Button.Style>
        <Style TargetType="Button">
            <Setter Property="FontFamily" Value="Georgia" />
            <Setter Property="FontSize" Value="40" />
            <Setter Property="Foreground" Value="White" />
            <Setter Property="Background" Value="Black" />
        </Style>
    </Button.Style>
</Button>

И эта, очевидно, мало чем полезная конструкция, будет работать. В этом случае вы уже не сможете повторно применить стиль к другим кнопкам.

Будет более разумно, если вы решите описать стили в отдельном ресурсе. Если вы пожелаете создать более строго специализированные стили, вы можете описать их в ресурсах контейнера, например в StackPanel или в Grid (такие стили можно будет применять только к элементам, вложенным в этот контейнер). Более того, один и тот же стиль можно описать на нескольких уровнях сразу (в контейнере StackPanel, содержащем кнопку, и внутри страницы, содержащей этот StackPanel). В такой ситуации Silverlight следует стандартному процессу поиска имен: сначала он ищет в ресурсах текущего элемента, затем в контейнере содержащем этот элемент, затем в следующем контейнере уровнем выше, и т.д., пока не найдет стиль с соответствующим именем. Если вы хотите, чтобы стиль был доступен в любой части кода вашего приложения, опишите его в ресурсах приложения (в файле App.xaml), поиск в котором происходит в последнюю очередь.