Главная » C#, Windows Runtime, XAML, Разработка для Windows 8 » Создание собственных элементов управления Windows Runtime

0

Шаблоны

Понятие шаблона

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

В предыдущих главах мы использовали такие  стили,  как  AppBarButtonStyle и BackButtonStyle, чтобы задать для простого  элемента Button характерные свойства (кнопка панели приложения и кнопка Back). При этом элемент Button не просто менял цвет и  размеры, но и принимал абсолютно новую форму, а  также  подключал  дополнительную анимацию  для  событий,  связанных со взаимодействием с пользователем.

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

Рассмотрим    стандартный    стиль    для    кнопки    на    панели    приложения (AppBarButtonStyle). Первое, что происходит внутри этого кода, это установка стандартных свойств кнопки:

<Setter Property="Foreground"

Value="{StaticResource AppBarItemForegroundBrush}"/>

<Setter Property="VerticalAlignment" Value="Stretch"/>

<Setter Property="FontFamily" Value="Segoe UI Symbol"/>

<Setter Property="FontWeight" Value="Normal"/>

Тут нет ничего интересного. А вот  на что нужно обратить внимание,  так это на  установку специального  свойства  Template.  Именно  с   помощью  этого свойства  и  задается внешний вид элемента  управления  «кнопка».  При этом шаблон элемента достаточно объемен, поэтому для его создания используется элемент-контейнер  ControlTemplate, который  может входить  в   состав стиля или  быть  самостоятельным элементом в   ресурсах Вашего приложения. Если ControlTemplate  задается  как  отдельный  элемент  (вне  стиля),  то  одним  из его атрибутов  является TargetType, задающий область  действия шаблона по отношению к указанным элементам.

Элемент ControlTemplate определяет дерево элементов,  которые  описывают новое представление  для выбранного элемента. Поскольку  дерево элементов может быть только одно и должно содержать родительский элемент, то внутри ControlTemplate обычно указывается один из доступных контейнеров. В случае кнопки этим контейнером является Grid. Внутри контейнера задаются дочерние элементы,  описывающие новое представление кнопки,  а  также  анимацию, связанную с переходом из состояния в состояние. Таким образом,  все достаточно просто: чтобы создать свой собственный элемент на  основе существующего, достаточно  определить  его  представление  (иногда  базируясь  на  некоторых обязательных   элементах),   а   также   анимации,   сопровождающие элемент в определенных состояниях.

Естественно, если мы определяем элемент, не описывая новый ControlTemplate, то элемент использует стандартное представление,  описанное при создании элемента. Это представление можно легко получить, воспользовавшись утилитой Expression Blend 5, о которой  пойдет речь в  следующем разделе. Эта утилита умеет копировать встроенный в  элемент шаблон, позволяя редактировать  его в виде ресурсов или встроенного в страницу стиля и использовать его для всех аналогичных элементов управления.

Чтобы посмотреть на шаблон, генерируемый Expression Blend 5, создайте пустой проект и добавьте на страницу приложения кнопку. Щелкнув правой кнопкой на новосозданном элементе управления, выберите команду контекстного меню Edit Template -> Edit a Copy:

Рис. 8.1.

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

Рис. 8.2.

Сгенерировав ресурсы, можно перейти в режим редактирования копии шаблона для создания новой обертки элемента управления. Обращаем Ваше внимание, что Blend встраивает шаблон элемента в стиль, задавая свойство Template. Ведь стиль позволяет задать дополнительные  свойства  элемента и является более удобным.

Для  простейших  элементов,  таких  как  кнопки,  можно  задавать  абсолютно произвольное представление. В более сложных случаях элемент может задавать список  частей,  которые  должны  обязательно  входить  в   его  составляющие. Элементы управления, обязательные для создания нового шаблона называются Parts (части). Чтобы указать  на  все  части,  элемент использует специальный атрибут TemplatePart:

 [TemplatePart(Name = "TextElement", Type = typeof(TextBlock))] [TemplatePart(Name = "UpButtonElement", Type = typeof(RepeatButton))] [TemplatePart(Name = "DownButtonElement", Type = typeof(RepeatButton))] public class MyControl: Control

В  этом  коде  декларируется новый элемент управления, в   визуальной  части которого обязаны присутствовать три элемента: текстовый блок и два элемента типа RepeatButton. Данный код надуманный и скорее является исключением, так как новые элементы управления пытаются обойти использование подобных атрибутов, реализуя интерфейсы и универсальное поведение.

Состояния и переходы

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

·                   описать возможные состояния;

·                   модифицировать текущее состояние внутри логики элемента управления;

·                   описать изменения для каждого из состояний в XAML;

·                   определить   дополнительные   характеристики    перехода   из    одного состояния в другое.

Чтобы  описать  возможные состояния  внутри  логики  элемента  управления, используется  атрибут  класса  TemplateVisualState.  Для   описания  элемента управления Button используется целых семь подобных атрибутов:

 [TemplateVisualState(Name = "Normal", GroupName = "CommonStates")] [TemplateVisualState(Name = "PointerOver", GroupName = "CommonStates")] [TemplateVisualState(Name = "Pressed", GroupName = "CommonStates")] [TemplateVisualState(Name = "Disabled", GroupName = "CommonStates")] [TemplateVisualState(Name = "Unfocused", GroupName = "FocusStates")] [TemplateVisualState(Name = "Focused", GroupName = "FocusStates")] [TemplateVisualState(Name = "PointerFocused", GroupName = "FocusStates")]

public class Button : ButtonBase

{

}

Из  приведенного синтаксиса  несложно  догадаться,  что  атрибут  принимает два параметра: имя состояния и имя группы. Группы вводятся для того, чтобы ограничить возможность пересечения  состояний. Так, кнопка не может быть нажата  и  отпущена  одновременно, она  может  находиться  только  в   одном состоянии из каждой группы.

Чтобы  обеспечить  переход  из  состояния  в    состояние,  внутри   реализации логики элемента управления достаточно воспользоваться статическим методом GoToState класса VisualStateManager:

private void UpdateStates(bool useTransitions)

{

if (isFocused)

{

VisualStateManager.GoToState(this, "Focused", useTransitions);

}

else

{

VisualStateManager.GoToState(this, "Unfocused", useTransitions);

}

}

Тут  метод принимает  имя  свойства  и  определяет, может ли  использоваться дополнительная анимация при переходе из одного состояния в другое.

Именно  метод  GoToState  мы  использовали при  определении   поведения приложения в различных режимах (Snapped, Filled и т. д.).

Теперь можно перейти к XAML. Тут и выполняется   вся работа по  изменению визуального представления элемента при переходе из одного состояния в другое. Это  делается  с  помощью  элемента  VisualStateManager, который  содержит описание всех состояний (VisualState), разбитых на группы (VisualStateGroup):

<VisualStateManager.VisualStateGroups>

<VisualStateGroup x:Name="CommonStates">

<VisualState x:Name="Normal"/>

<VisualState x:Name="PointerOver">

<Storyboard>

<ObjectAnimationUsingKeyFrames Storyboard.TargetName="BackgroundGlyph" Storyboard.TargetProperty="Foreground">

<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource

AppBarItemHoverBackgroundBrush}"/>

</ObjectAnimationUsingKeyFrames>

<ObjectAnimationUsingKeyFrames Storyboard.TargetName="Content" Storyboard.TargetProperty="Foreground">

<DiscreteObjectKeyFrame KeyTime="0"

Value="{StaticResource AppBarItemHoverForegroundBrush}"/>

</ObjectAnimationUsingKeyFrames>

</Storyboard>

</VisualState>

<VisualState x:Name="Pressed">

. . . . .

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

Наверное, Вы обратили внимание, что каждая анимация имеет свойство KeyTime или Duration, которому присвоено значение 0. Это  означает,  все  изменения происходят мгновенно. Чтобы сделать  анимацию более плавной, пользуются специальным элементом  VisualTransition, который и позволяет задать время выполнения всего StoryBoard.

<VisualTransition From="Normal" GeneratedDuration="0:0:3" To="PointerOver"/>

Таким образом, создание шаблона – задача тривиальная. Между тем, Expression Blend позволяет еще больше упростить эту задачу, предоставляя специальный режим редактирования шаблона. В этом режиме разработчик получает доступ к таким окнам, как States и Parts, а также ко всему дереву элемента управления. Окно Parts позволяет отобразить все обязательные элементы, что дает возможность отлеживать ошибки создания шаблона и избавляет от необходимости  изучать документацию для каждого элемента, чтобы узнать, какие у него обязательные составляющие. Окно States отображает все  состояния, разбитые по группам, с возможностью  создавать переходы и редактировать анимацию в  каждом из состояний.

Рис. 8.3.

Сергей Лутай, Сергей Байдачный, Windows 8 для C# разработчиков

По теме:

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