Главная » Silverlight » Стили и поведения

0

Приложения Silverlight выглядели бы весьма уныло, если бы в них использова­лись только обычные кнопки и стандартные элементы управления. К счастью, в Silverlight встроен ряд средств, позволяющих вдохнуть жизнь в базовые элементы и унифицировать "стильные" компоненты интерфейса. В этой главе рассматриваются два наиболее важных средства, предназначенных для этого, — стили и поведения.

Стили — полезный инструмент упорядочения и повторного использования резуль­татов форматирования. Вместо загромождения файла XAML повторяющейся разметкой многочисленных деталей интерфейса (шрифтов, цветов, пустых полосок и т.д.), гораздо лучше создать один хорошо инкапсулированный стиль. Его можно применить в любом месте интерфейса, установив единственное свойство.

Поведения — более амбициозный инструмент, предназначенный для повторного ис­пользования кода пользовательского интерфейса. Базовая идея состоит в инкапсуляции функциональности интерфейса (например, кода, позволяющего перетаскивать элемент). Если у вас есть нужное поведение, вы можете подключить его к любому элементу с по­мощью одной или двух строк разметки XAML, сэкономив много времени на создание и отладку кода. В настоящее время поведения — относительно новое, развивающееся средство, поэтому в ближайшем будущем ожидается появление большого количества полезных готовых поведений, разработанных независимыми поставщиками программ­ного обеспечения.

Новые средства. В Silverlight 3 добавлены два новых средства стилизации пользовательского интерфейса, и оба заимствованы из WPF. Теперь вы можете изменить стиль элемента в коде и создать стиль, наследующий другой стиль. Поведения — совершенно новое средство, введенное в Expression Blend 3.

Стили

Стиль — этого коллекция свойств, применяемая к элементу. В Silverlight стили по­зволяют упростить разметку XAML путем удаления повторяющихся параметров форма­тирования из дескрипторов.

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

Сравнение стилей Silverlight и WPF

Если вы использовали стили WPF, то непременно заметите, насколько стили Silverlight ограничены по сравнению с ними. Ниже перечислены операции, которые можно выполнять со стилями WPF, но не Silverlight.

Автоматическое применение стилей к типам элементов (например, ко всем кнопкам окна), -у* Использование триггеров стилей для изменения стиля элемента управления при изменении его свойства, -у- Применение стиля к элементам разных типов (например, к текстовым блокам и кнопкам), ?у» Использование стилей для присвоения контейнеру свойств, передаваемых дочерним элементам. -Ф- Подключение обработчиков событий с помощью стилей.

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

Определение стиля

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

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

</Style>

</UserControl.Resources>

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

Объект стиля содержит коллекцию Setters, которая, в свою очередь, содержит на­бор объектов Setter, по одному на каждое свойство элемента. Объект Setter может устанавливать только зависимое свойство, другие свойства для него недоступны. На практике это не очень жесткое ограничение, потому что почти все свойства элемен­тов Silverlight являются зависимыми. Объекты Setter обрабатывают любые зависимые свойства, даже те, которые управляют функциональностью, а не внешним видом эле­мента. Например, с помощью стиля в текстовом блоке можно устанавливать свойства 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>

В некоторых случаях установить свойство с помощью простой строки атри­бута нельзя. Это происходит, например, при создании сложной кисти, такой как LinearGradientBrush или ImageBrush. Решить проблему несложно с помощью знакомо­го вам приема в разметке XAML, состоящего в замене атрибута вложенным элементом. В приведенной ниже разметке устанавливается фон кнопки.

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

</Style>

Более мощные стили могут устанавливать объекты преобразований, создавать ви­зуальные эффекты и управлять шаблонами. Все это позволяет радикально изменить внешний вид элемента.

Применение стиля

В каждом элементе Silverlight можно использовать один стиль. Стиль подключается к элементу с помощью свойства Style, определенного в базовом классе FrameworkElement. Например, чтобы подключить приведенный выше стиль BigButtonStyle к кнопке, нуж­но указать для нее ресурс стиля.

<Button Style="{StaticResource BigButtonStyle}"

Content="Стилизованная KHonKa"x/Button>

На рис. 12.1 показана страница с двумя кнопками, в которых используется один и тот же стиль BigButtonStyle.

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

Использование стилей предоставляет много преимуществ. Стили не только позво­ляют группировать параметры элементов, но и упрощают разметку, облегчая примене­ние параметров. Наиболее существенное преимущество состоит в том, что стили мож­но применять, не беспокоясь о том, какие свойства уже установлены. В предыдущем примере параметры шрифта сгруппированы в стиле BigButtonStyle. Если позже вы решите добавить пустые полоски, нужно будет лишь добавить в стиль объекты Setter для свойств Padding и Magrin, не трогая уже установленные свойства. Пустые полоски будут автоматически присвоены всем кнопкам, в которых используется данный стиль.

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

Динамические стили

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

Ниже приведен код, извлекающий стиль BigButtonStyle из коллекции ресурсов страницы и применяющий его к объекту Button с именем cmd.

cmd.Style =

(Style)this.Resources["AlternateBigButtonStyle"];

Стиль можно извлечь даже из отдельного файла, содержащего словарь ресурсов про­екта, или из сборки, на которую есть ссылка. Для извлечения стиля из словаря нужно создать объект ResourceDictionary и предоставить ему правильный адрес URI.

ResourceDictionary resourceDictionary = new ResourceDictionary();

resourceDictionary.Source = new Uri("/Styles/AlternateStyles.xaml", UriKind.Relative);

В данном примере предполагается, что словарь ресурсов находится в файле AlternateStyles . xaml, который, в свою очередь, находится в папке Styles. Словарь ре­сурсов должен быть скомпилирован в файл. Для этого откройте окно Properties и при­свойте свойству Build Action (Действие построения) значение Content (Содержимое).

Передав объекту ResourceDictionary адрес нужного стиля, можно извлечь его объект.

Style newStyle =

(Style)resourceDictionary["BigButtonStyle"] ;

cmd.Style = newStyle;

Чтобы удалить стиль, присвойте свойству Style значение null.

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

Наследование стилей

В некоторых ситуациях желательно использовать свойства одного стиля в качестве основы при создании другого, более специального, стиля. Для наследования свойств другого стиля нужно установить атрибут BasedOn.

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

<Style x:Key="EmphasizedBigButtonStyle" TargetType="Button" BasedOn="{StaticResource BigButtonStyle}"> <Setter Property="BorderBrush" Value="Black" /> <Setter Property="BorderThickness" Value="5" /> </Style>

</UserControl.Resources>

В стиле BigButtonStyle определены четыре свойства. Стиль EmphasizedBigFontBut- tonStyle наследует эти свойства от стиля BigFontButtonStyle и, кроме того, определя­ет два дополнительных свойства, рисующих толстую рамку по периметру кнопки. Такая конструкция, состоящая из двух частей, позволяет применить только параметры шриф­та или комбинацию параметров шрифта и цвета. Можно создать дополнительные сти­ли, наследующие параметры шрифта и цвета (не обязательно обе группы параметров).

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

Совет. Как ни удивительно, однако наследующий стиль не обязательно должен иметь то же значение свойства TargetType, что и наследуемый. Это означает, что можно создавать производные стили, применяющие одни и те же параметры форматирования к элементам разных типов. Однако при попытке унаследовать процедуру установки свойства, которого в целевом элементе не существует, генерируется ошибка. Например, свойство FontFamily есть у классов TextBlock и Button, поэтому можно установить его в стиле кнопки и создать стиль TextBlock, наследующий стиль кнопки. Однако свойство IsEnabled есть только у кнопки, поэтому, если стиль кнопки устанавливает свойство IsEnabled, он не может быть унаследован стилем текстового блока.

Наследование стилей усложняет приложение

На первый взгляд наследование кажется очень удобным средством, однако на практике его применяют редко. Это объясняется тем, что наследование стилей порождает те же проблемы, что и наследование кодов: зависимости од­них стилей от других делают приложение хрупким. Например, при использовании приведенной выше разметки вы будете вынуждены поддерживать одинаковые параметры шрифта для обоих стилей. При попытке изменить стиль BigButtonStyle, будет автоматически изменен также стиль EmphasizedBigButtonStyle (конечно, если не добавить явно дополнительные процедуры установки свойств, переопределяющие унаследованные значения). В примере с двумя стилями эта проблема выглядит тривиальной, однако в реальных приложениях, содержа­щих много стилей, она весьма докучливая. Обычно стили классифицируются на основе типа и назначения содер­жимого. Например, в приложениях для торговли могут использоваться такие стили, как ProductTitleStyle, ProductTextStyle, HighlightQuoteStyle, NavigationButtonStyle и т.д. Если унаследовать стиль ProductTitleStyle от ProductTextStyle (возможно, у них должны использоваться одинаковые шрифты), то позже проблемы возникнут при попытке присвоения стилю ProductTextStyle параметров, которые не должны быть при­менены к стилю ProductTitleStyle. Вы будете вынуждены явно переопределить параметры стиля Product­TitleStyle. В результате приложение усложняется и концепция повторного использования стилей теряет смысл. Прежде чем применить наследование стилей, подумайте, есть ли для этого достаточно веские причины. Не забывай­те, что в будущем наследование может породить коварные проблемы. Веской причиной применения наследования стилей может быть их похожее назначение, например, если второй стиль является частным случаем первого, причем наследуется много параметров, а переопределить нужно всего лишь несколько.

Организация стилей

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

Ресурсы и стили не обязательно должны использоваться вместе. Например, стиль кнопки можно определить, заполнив коллекцию Style непосредственно в кнопке (как видите, ресурсы не применяются).

<Button C0ntent="CTHjM30BaHHaH кнопка"> <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 применяет стандартную процедуру разрешения ресурсов (см. главу 2): сначала проверяется коллекция ресурсов текущего элемента, затем — родительского элемента, после этого — контейнера и так до тех пор, пока не будет найден стиль с заданным именем.

Если стиль нужно применять во всем приложении, определите его в коллекции ре­сурсов приложения (файле Арр. xaml) — это последнее место, в котором Silverlight будет его искать. А еще лучше — разместите его в отдельном словаре ресурсов, размещенном в коллекции ресурсов каждой страницы, в которой он используется (см. главу 2).

Источник: Мак-Дональд, Мэтью. Silverlight 3 с примерами на С# для профессионалов. : Пер. с англ. —- М. : ООО «И.Д. Вильяме», 2010. — 656 с. : ил. — Парал. тит. англ.

По теме:

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