Элементы управления стилем (Styling Controls) в Silverlight

ОГЛАВЛЕНИЕ

Данная статья продемонстрирует способ модификации внешнего вида элементов управления вашего приложения. Существует множество способов выполнения этого, а также множество инструментов для реализации.

Я постараюсь сфокусироваться на трех чаще всего встречающихся:

  1. Использование элементов управления как есть - при этом немного модифицируя их внешний вид установив стили внутри XAML (либо через окно свойств в Visual Studio или Blend) 
  2. Создание многократно используемого объекта Style для предоставления шаблонного вида элементам управления, которые выполняют одинаковые функции (к примеру, все ярлыки выглядят одинаково) 
  3. Создание шаблонов для кардинального изменения внешнего вида элементов управленияс сохранением при этом их функциональности.

Настройка стилей внутри тега (inline)

Простейшим и, скорее всего, наиболее распространенным способом установки стиля является установка в Xaml, выполняя это в Visual Studio 2008 (прямо в разметке) либо в Blend (при помощи закладки свойств). Чтобы снизить риск встречи с проблемами на нашем пути, мы начнем с созданного в статье пропривязку данных приложение, которое вы можете загрузить тут.

Откройте проект в Blend и исследуйте элементы управления - вы увидите табличную сетку с двумя колонками и шестью строками. Левая часть имеет пять элементов TextBlocks и кнопку, а правая часть имеет два TextBlocks, один ListBox, CheckBox и один TextBox. Откройте этот же проект в Visual Studio и исследуйте разметку - элементы управления не полностью оформлены (за исключением выравнивания) , как это показано на рисунке 6-1

Рисунок 6-1. Проект в Blend и Visual Studio

Я обвел TitlePrompt в Blend (Objects, Timeline и Properties), чтобы доказать, что не так много свойств было настроено. Это можно увидеть в Xaml из Visual Studio 2008. Вам может понадобиться оформить каждому ярлыку свой шрифт, к примеру, Comic Sans MS с размером 24. Вы можете выполнить это явно в разметке либо Blend, либо Visual Studio, но для данной статьи (и для реального приложения) я буду редактировать Xaml и Code в Visual Studio, а также я буду использовать Blend для редактирования непосредственно на поверхности разработки и при помощи окна свойств.

Для того, чтобы отредактировать Xaml вручную, начните вписывать необходимые вам значения - Intellisense поможет вам с синтаксисом, как это показано на рисунке 6-2 

Рисунок 6-2. Установка размера шрифта в Xaml

Результатом будет мгновенное отображение в окне режима дизайнера Visual Studio, как показано на рисунке 6-3

Рисунок 6-3. Добавление стилей к Xaml вручную

Настройка стилей в качестве свойств в Blend

В качестве альтернативы настройки стилей в Xaml попробуйте сохранить файл и переключиться в Blend. После того как вы ответите "Yes" на запрос об обновлении проекта, щелкните по AuthorPrompt в закладке объектов и шаблонов (Objects and Timeline) и затем откройте закладку свойств, и оттуда в закладке Text установите шрифт Comic Sans MS с размером 24. Вы сразу увидите изменения, как это показано на рисунке 6-4

Рисунок 6-4. Настройка стилей в качестве свойств в Blend

Xaml также обновлен, как вы уже могли бы заметить в режиме разделения либо в режиме Xaml в Blend и Visual Studio 2008, 

<TextBlock x:Name="AuthorPrompt" Text="Author: "
       VerticalAlignment="Bottom"
       HorizontalAlignment="Right"
       Grid.Row="1" Grid.Column="0"
       FontFamily="Comic Sans MS"
       FontSize="24" />

Установка стилей в качестве ресурсов (Resources)

В лучшем случае вам понадобится присвоить всем ярлыкам шрифт Comic Sans MS с размером в 24, и они должны быть все горизонтально выровнены к правому краю (с отступом в 10), выровнены по нижнему краю и быть синего цвета. 

Установка всего этого вручную может быть достаточно утомительным занятием, но вы с легкостью можете создать ресурс стиля (Style Resource), назвать его как вам угодно, а затем применить все эти элементы управления. Это позволяет вам создавать шаблонный внешний вид, при этом весь стиль будет храниться в единственном месте, где вы сможете производить изменения.

Восстановление свойств

Первым шагом будет восстановление стандартного стиля для всех ярлыков. Заново откройте проект в Blend и, зажав клавишу control, щелкните по пяти элементам управления в панели Objects and Timelines , тем самым подсветив все. Обратите внимание на то, что в окне свойств напротив горизонтального и вертикального выравнивания стоят белые точки. Это означает, что данные значения были настроены - нажмите на точку, и появится меню, позволяющее вам восстановить данные свойства, как это показано на рисунке 6-5

Рисунок 6-5. Восстановление свойств

Как только все белые точки будут убраны нажмите на каждый ярлык по отдельности и восстановите его индивидуальные свойства (в нашем случае только у TitlePrompt и AuthorPrompt будет восстановлено свойство Text). 

Бегло рассмотрите Xaml - TextBlocks ярлыков теперь имеют свои стандартные свойства Text и свое расположение в табличной сетке,

<TextBlock x:Name="TitlePrompt" Text="Title:  "      Grid.Row="0"  Grid.Column="0"/>  

<TextBlock x:Name="AuthorPrompt" Text="Author: " Grid.Row="1" Grid.Column="0" />

<TextBlock x:Name="ChapterPrompt" Text="Chapters: " Grid.Row="2" Grid.Column="0" />

<TextBlock x:Name="MultipleAuthorPrompt" Text="Multiple authors?: " Grid.Row="3" Grid.Column="0" />

<TextBlock x:Name="QOHPrompt" Text="Quantity On Hand: " Grid.Row="4" Grid.Column="0" />

Создание ресурса стиля (Style Resource)

Давайте создадим стиль, который может быть применен ко всем ярлыкам. Начните в Blend с выбора Object > Edit Style > Create Empty. Это вызовет диалоговое окно создания стиля (Create Style). Вы можете расположить ваш стиль в текущем документе Xaml, но это ограничит размах вашего стиля в пределах данного документа. Обычно предпочитается расположение нового ресурса стиля в App.xaml, тем самым делая его доступным во всем приложении. Вы можете сделать это, выбрав кнопку с зависимой фиксацией Application. Дайте вашему стилю название (Prompt), как это показано на рисунке 6-6

Рисунок 6-6. Создание стиля подсказки для приложения 

Обратите внимание на то, что закладки появляются в верхней части окна режима дизайнера, как это показано на рисунке 6-7

Рисунок 6-7. Закладки

Если вы нажмете на левую закладку, AuthorPrompt вернет вас в нормальный режим дизайнера. Нажав на вторую закладку вы переместитесь обратно к созданию вашего стиля. Убедитесь в том, что у вас открыто окно свойств и начните настраивать свойства вашего стиля. Вам наверняка будет удобнее находиться в режиме "split", тем самым вы сможете увидеть результат в App.xaml. 

Рисунок 6-8. Установка свойств стиля

На рисунке 6-8 показано окно свойств и белые точки указывают те свойства, которые я настроил для нашего стиля подсказок (Prompt), в то время как пример 6-1 демонстрирует Xaml сгенерированный в App.xaml.

Пример 6-1. Стиль подсказки

<Application.Resources>
   <Style x:Key="Prompt" TargetType="TextBlock">
      <Setter Property="HorizontalAlignment" Value="Right"/>
      <Setter Property="VerticalAlignment" Value="Bottom"/>
      <Setter Property="Margin" Value="0,0,10,0"/>
      <Setter Property="FontFamily" Value="Comic Sans MS"/>
      <Setter Property="FontSize" Value="24"/>
      <Setter Property="Foreground" Value="#FF0000FF"/>
   </Style>
</Application.Resources>

Вы все же можете написать стиль вручную, хотя сложные стили будет гораздо легче создать при помощи Blend.

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

Для того, чтобы применить стиль ко всем подсказкам, Blend предлагает вам два подхода. Первый способ применения стиля – щелчок по элементу TextBlock, к которому вы хотите применить стиль (т.е. TitlePrompt) в закладке Objects and Timeline, и затем нажатие на опцию меню Object > Edit Style > Apply Resources > Prompt. 

Готово! Стиль был применен и вы можете увидеть это как в панели истории, так и в Xaml

Рисунок 6-9. Применение стиля

В качестве альтернативы вы можете перетащить стиль из закладки ресурсов прямо на элемент управления, тем самым вызвав диалоговое окно, спрашивающее вас о том, хотите ли вы связать стиль, как это показано на рисунке 6-10

Рисунок 6-10. Перетаскивание ярлыка

Как только вы нажмете на "Style" будет применен стиль Prompt к тому элементу управления, который вы перетащили! Когда будут применены все стили вам придется настроить размер элемента управления, чтобы вместилась более длинная подсказка. Но вы можете теперь применить шаблонный стиль ко всем подсказкам и если вы решите изменить их цвет с синего на черный, то вы можете сделать это изменив ресурс вместо того, чтобы изменять каждый в отдельности.


Шаблоны и скиннинг

Иногда вам может понадобиться (полностью) изменить внешний вид элемента управления полностью, придав ему совершенно новый вид без каких-либо изменений в его функциональности. Тут уместно применять шаблоны Silverlight, менеджер визуальных состояний (Visual State Manager) и модель частей и состояния (Parts and State Model). 

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

Модель частей и состояний

Silverlight обладает некоторыми радикальными изменениями по сравнению с предыдущими технологиями (такими, как ASP.NET, WinForms и т.д.). В старых технологиях каждый элемент имел свой определенный внешний вид, и мы, как разработчики, были несколько ограничены в использовании стилей и, впоследствии, скиннинга. В Silverlight каждый элемент управления, предоставленный компанией Microsoft, поддерживает новую модель частей и состояний (Parts and States Model), которая вызывает строгую сеперацию между логикой элемента управления и его внешним видом. 

Преимуществом данного подхода является то, что разработчик может с легкостью изменить внешний вид элемента отдельно от его функциональности, тем самым обладая свободой в действиях, особенно при работе с дизайнерами. Внешний вид инкапсулирован в шаблоне, использующем модель Parts and State, и регулируетсяменеджером визуальных состояний (Visual State Manager) (VSM). Expression Blend знает, как читать и создавать части и состояния, тем самым делая скиннинг элементов управления практически тривиальной задачей ... во всяком случае тогда, когда вы знаете, как это сделать.

Модель частей и состояний построена на следующих ключевых принципах: 

  1. Части (Parts) 
  2. Состояния (States) и Группы состояний (State Groups) 
  3. Переходы (Transitions) 

Части (Parts)

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

Состояния и группы состояний

Каждый элемент управления имеет несколько состояний ("States") - определенных разработчиком элемента управления. Как показано на рисунке 6-11, кнопка имеет четыре стандартных состояния ("Common States") 

  • Normal - нормальное
  • MouseOver - наведенное
  • Pressed - нажатое
  • Disabled - отключенное 

А также она обладает двумя состояниями фокуса ("Focus States")

  • Focused - сфокусированное
  • Unfocused - без фокуса 

Обратите внимание на то, что вторые два состояния выделены в отдельную группу состояний. Идея заключается в том, чтобы создавать группы для уменьшения потенциального "взрыва" комбинаций состояний (то есть используя группы состояний, вы потенциально уменьшаете количество различных состояний с 64 до 12, путем разделения смешанных состояний в группы по три или четыре)

Рисунок 6-11. Button States and State Groups

Переходы

То, что показано на рисунке 6-11 является обходным путем - я вырезал маркеры времени переходов для того, чтобы упростить изображение, которое в оригинале должно выглядеть следующим образом 

Рисунок 6-12. Состояния со значениями времени 

Цифры, которые я обвел являются временами переходов (измеряются в секундах). Они указывают длительность перехода из одного состояния к другому.  

Два значения, которые обведены красным цветом, являются стандартными для двух групп состояний, в то время как два значения, обведенные белым цветом, являются переписанными. Если вы исследуете тщательнее изображение, то увидите стрелку со звездочкой, которая показывает состояние MouseOver, тем самым указывая, что данный промежуток времени в 0.2 секунды необходим для перехода из любого состояния в состояние MouseOver, и во втором случае 0.1 секунды - для переключения из любого состояния в Pressed. То, что произойдет во время перехода, определяется самим переходом (Transition), который является раскадровкой (основой анимации) и будет описан ниже. Основной идеей переходов является возможность избегать прыжков из одного состояния в другое, а также более гладкое изменение между состояниями.

Опять же, исследовав существующий шаблон, мы можем понять, как элементы управления, предоставленные компанией Microsoft, обрабатывают данные переходы. Щелкните по состоянию Pressed в режиме Object and Timeline - State изменяется в Pressed и подсвечиваются две части: Background Gradient (фоновый градиент) и Downstroke (подчеркивание).  

При расширении данных частей при помощи стрелок, мы увидим те подчасти, которые были изменены при переходе кнопки в состояние Pressed, как это показано на рисунке 6-13 

Рисунок 6-13. Исследуем шаблон на Button Pressed 

Обратите внимание на то, что под фоновым градиентом заливка состоит из четырех остановок Gradient и что все четыре изменяют свои цвета, но второй изменяет также и свое положение. Вы можете нажать на каждый цвет поочереди и, исследовав окошко свойств и/или Xaml, увидеть все изменения. Это особенно важно в случае со второй остановкой, когда изменяются цвет и расположение, как это показано на рисунке 6-14

Рисунок 6-14. Состояние нажатой кнопки (Button Pressed)


Скиннинг элемента управления

Давайте создадим полноценный шаблон с нуля и увидим, что произойдет. Понять сам способ работы и полная реализация - это не одно и то же. Вернемся к проекту, с которым мы работали, и сделаем некоторые изменения до того, как мы начнем скиннинг кнопки. Перетащите стиль подсказки на пять элементов, если вы ещё не сделали этого (последние два выйдут за рамки, но это нормально). Как только вы сделаете это, щелкните дважды по пользовательскому элементу управления (UserControl) в Objects and TimeLine и, захватив справа элемент управления, измените его ширину к 500. Теперь вам понадобится изменить размер у левой колонки, и чтобы это было легко - перейдите в режим Split и просто настройте максимальную ширину (Max) с 150 на 250. Ваш элемент управления теперь должен выглядеть примерно так

Рисунок 6-15. Готовность к скиннингу кнопки изменения книги

Создание круглой кнопки

Мы хотим изменить внешний вид кнопки с нормальной формы на более привлекательную круглую форму со словом Change в ней. Кнопка будет распознавать курсор тогда, когда он будет над ней и будет поворачиваться при нажатии. Также текст будет затемнен в тех случаях, когда она не будет доступна. Для того, чтобы начать, найдите кнопку в закладке Objects and Timeline (и назовите ее Change) и щелкните правой кнопкой мыши. Выберите Edit Control Parts > Create Empty, как это показано на рисунке 6-16.

Рисунок 6-16. Создание пустого шаблона для кнопки

В диалоговом окне назовите новый шаблон RoundButon и расположите его в приложении (что создаст новый ресурс в App.xaml). Blend перейдет в режим редактирования шаблона (Template), который отличается от всех тем, что имеет в наличии закладки в верхней части экрана. Ваш пустой шаблон будет иметь табличную сетку. Наша кнопка будет состоять из эллипса (Ellipse), который также обладает текстом и будет заполнен линейным градиентом. 

Начните с расположения эллипса в табличной сетке точно так же, как вы бы сделали это в нормальном режиме дизайнера. Установите ширину и высоту для начала в 75 и установите выравнивание в растягивающее значение (Stretch). Мы хотим заполнить эллипс радиальным градиентом (в отличие от стандартного линейного). Щелкните по кнопке кисти заполнения, щелкните по кнопке кисти с градиентом, и затем в нижней левой части закладки кистей (Brushes) нажмите на опцию Radial gradient, как это показано на рисунке 6-17 

Рисунок 6-17. Выбор градиентной кисти

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

<Ellipse Width="75" Height="75"
   Margin="0,0,10,10" x:Name="ButtonEllipse" >
   <Ellipse.Fill>
    <RadialGradientBrush GradientOrigin="0.2,0.2" >
      <GradientStop Color="White" Offset="0.2"/>
      <GradientStop Color="Blue" Offset="1"/>
    </RadialGradientBrush>
   </Ellipse.Fill>
</Ellipse>

Ваш элипс должен выглядеть следующим образом

Рисунок 6-18. Эллипс с радиальным градиентом

Далее мы хотим добавить текст (в частности, слово Change!) к кнопке. Для этого перетащите текстовый блок куда-нибудь над эллипсом и затем переключитесь в окошко свойств, где вы сможете изменить его размер и позицию , как это показано на рисунке 6-19

Рисунок 6-19. Свойства, установленные для кнопки

Рисунок 6-19 был уменьшен для того, чтобы смог поместиться - были убраны части, которые не были изменены. На данном этапе ваша кнопка должна выглядеть примерно так

Рисунок 6-20. Кнопка с добавленным текстом

Управление состоянием кнопки

Как уже обсуждалось выше, кнопка обладает четырьмя стандартными состояниями ("Common states") и двумя состояниями фокуса ("Focus states"). Теперь нам надо настроить внешний вид для каждого из этих состояний, и при желании настроить время перехода между данными состояниями. 

Состояние MouseOver

Давайте начнем с добавления кнопке действияпри наведении курсора на нее. Это простой переход, но нам необходимо оформить его для эллипса, поэтому нажмите на эллипс в панели Objects and Timeline и затем в закладке переходов (Transform) на кнопку масштабирования, как показано далее 

Рисунок 6-21. Преобразование масштаба элипса

При нажатии на кнопку масштабирования значения x и y изменяются в 1. Нажав на MouseOver и введя 1.2 в X и Y вы указываете Blend на то, что в состоянии MouseOver кнопка расплывается на 20%. 

Для проверки нажмите на Page.xaml в закладках и возвратитесь в режим редактирования. Удалите существующую измененную кнопку, нажмите на закладку ресурсов и перетащите вашу новую кнопку на полотно. Переключитесь к свойствам, назовите вашу кнопку Change (существует код, который зависит от кнопки, названной Change) и запустите приложение.  

Не нажимая на кнопку, передвиньте курсор на нее и обратно. Она изменяет размеры, но выглядит это все по-мультяшески. Изменения появляются внезапно (выглядят внезапными) - щелкните правой кнопкой мыши по кнопке и выберите Edit Control Parts> Edit Template, тем самым вернувшись в режим редактирования шаблона. Обратите внимание на то, что стандартный переход равен 0 секунд. Давайте изменим этот на 0.2 секунды и заново запустим - вы увидите огромную разницу. 

Состояние Pressed

Наверняка, наиболее интересным дизайном является тот, что происходит при нажатии кнопки. В нашем случае все будет достаточно просто - кнопка просто повернется и впадет. Нажмите на Pressed, тем самым указывая, что это именно то состояние, которое вы хотите настроить. Нажмите на Ellipse для того, чтобы указать, что вы хотите изменить cвойства эллипса. В окошке свойств нажмите на вторую кнопку (rotate) в окне Render Transforms (обработать переходы) и установите угол поворота в 25 градусов. Далее нажмите на первую кнопку (transition) и измените с 0 на 5. 

Переход происходит нормально, но почему-то не выполняется поворот. Конечно же, как мы можем увидеть поворот круглой кнопки? Вы можете вернуться к редактированию шаблона и сделать круг более эллиптическим (то есть установить ширину, равную 90) , что сделает поворот видимым, но не очень красивым.

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

Рисунок 6-22. Поворот текста при нажатии кнопки

Вы можете выполнить это, переключившись обратно к шаблону. На этот раз сделайте это, переключившись к закладке ресурсов (Resources), развернув App.xaml и щелкнув дважды по RoundButton. Теперь вы можете щелкнуть ButtonEllipse и вернуть поворот, а затем нажать на ButtonText и установить угол поворота. Красиво, правда?

Состояние Disabled

Последнее состояние, которое вам необходимо установить, является Disabled. Нажмите на ButtonText - и давайте изменим ее цвет с белого на серый, для того чтобы указать неактивность кнопки. Поскольку изменение цвета может произойти очень быстро, нажмите на AddTransition в пределах кнопки Disabled, как это показано на рисунке 6-23

Рисунок 6-23. Добавление переключения 

Выберите первую опцию (из любого состояния - в отключенное) и установите время в 0.1 секунды. Нажмите опять на кнопку добавления перехода (Add Transition) , выберите на этот раз Disabled > * и установите переход обратно в любое состояние в значение 0.1 секунда - состояния должны выглядеть так, как это показано на рисунке 6-24

Рисунок 6-24. Окно переключения состояния а также время специализированных переключений

Скачать исходники примеров

Jesse Liberty