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

Вы можете настроить визуальную структуру и визуальное поведение элемента управления, создав шаблон элемента управления в среде XAML. У элементов управления много свойств, таких как Background, Foreground и FontFamily, которые можно задать, чтобы указать различные аспекты вида элемента управления. Однако настройка этих свойств позволяет вносить ограниченные изменения. Вы можете указать дополнительные настройки, создав шаблон с помощью класса ControlTemplate. Здесь мы покажем, как создать ControlTemplate для настройки вида элемента управления CheckBox.

Важные API: класс ControlTemplate и свойство Control.Template

Пример пользовательского шаблона элемента управления

По умолчанию элемент управления CheckBox помещает свое содержимое (строку или объект рядом с CheckBox) справа от поля выбора, а флажок указывает, что пользователь выбрал CheckBox. Эти характеристики представляют визуальную структуру и визуальное поведение CheckBox.

Здесь CheckBox использует шаблон по умолчанию ControlTemplate, показанный в состояниях Unchecked, Checked и Indeterminate.

Шаблон по умолчанию CheckBox

Эти характеристики можно изменить, создав ControlTemplate для CheckBox. Например, если содержимое поля флажка должно быть ниже поля выбора, а для указания того, что пользователь установил флажок, следует использовать X. Эти характеристики указываются в ControlTemplate элемента управления CheckBox.

Чтобы использовать пользовательский шаблон с элементом управления, ControlTemplate назначается свойству Template элемента управления. Вот CheckBox, использующий ControlTemplateпод названием CheckBoxTemplate1. Мы покажем код XAML (Extensible Application Markup Language) для ControlTemplate в следующем разделе.

<CheckBox Content="CheckBox" Template="{StaticResource CheckBoxTemplate1}" IsThreeState="True" Margin="20"/>

Вот как этот класс CheckBox выглядит в состояниях Unchecked, Checked и Indeterminate после применения нашего шаблона.

Пользовательский шаблон CheckBox

Указание визуальной структуры элемента управления

При создании ControlTemplate мы объединяем объекты FrameworkElement, чтобы создать единый элемент управления. У ControlTemplate должен быть только один FrameworkElement в качестве корневого элемента. Корневой элемент обычно содержит другие объекты FrameworkElement. Такое сочетание объектов формирует визуальную структуру элемента управления.

Данный код XAML создает ControlTemplate для CheckBox, указывающий, что содержимое элемента управления находится под полем выбора. Корневой элемент — Border. Этот пример предлагает Path создать X, указывающий на то, что пользователь выбрал CheckBox, и Ellipse, указывающий на неопределенное состояние. Обратите внимание, что свойству Opacity задано значение 0 в Path и Ellipse, так что по умолчанию последние не выводятся.

TemplateBinding связывает значение свойства в шаблоне элемента управления и значение какого-либо другого предоставленного свойства элемента управления-шаблона. TemplateBinding может использоваться только в пределах определения ControlTemplate в XAML. См. подробнее в разделе Расширение разметки TemplateBinding.

Примечание

Начиная с Windows 10, версия 1809 (SDK 17763), вы можете использовать расширения разметки x:Bind вместе с TemplateBinding. См. подробнее в разделе Расширение разметки TemplateBinding.

<ControlTemplate x:Key="CheckBoxTemplate1" TargetType="CheckBox">
    <Border BorderBrush="{TemplateBinding BorderBrush}"
            BorderThickness="{TemplateBinding BorderThickness}"
            Background="{TemplateBinding Background}">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="*"/>
                <RowDefinition Height="25"/>
            </Grid.RowDefinitions>
            <Rectangle x:Name="NormalRectangle" Fill="Transparent" Height="20" Width="20"
                       Stroke="{ThemeResource SystemControlForegroundBaseMediumHighBrush}"
                       StrokeThickness="{ThemeResource CheckBoxBorderThemeThickness}"
                       UseLayoutRounding="False"/>
            <!-- Create an X to indicate that the CheckBox is selected. -->
            <Path x:Name="CheckGlyph"
                  Data="M103,240 L111,240 119,248 127,240 135,240 123,252 135,264 127,264 119,257 111,264 103,264 114,252 z"
                  Fill="{ThemeResource CheckBoxForegroundThemeBrush}"
                  FlowDirection="LeftToRight"
                  Height="14" Width="16" Opacity="0" Stretch="Fill"/>
            <Ellipse x:Name="IndeterminateGlyph"
                     Fill="{ThemeResource CheckBoxForegroundThemeBrush}"
                     Height="8" Width="8" Opacity="0" UseLayoutRounding="False" />
            <ContentPresenter x:Name="ContentPresenter"
                              ContentTemplate="{TemplateBinding ContentTemplate}"
                              Content="{TemplateBinding Content}"
                              Margin="{TemplateBinding Padding}" Grid.Row="1"
                              HorizontalAlignment="Center"
                              VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
        </Grid>
    </Border>
</ControlTemplate>

Указание визуального поведения элемента управления

Визуальное поведение описывает внешний вид элемента управления в определенных состояниях. У элемента управления CheckBox есть три состояния выставления: Checked, Unchecked и Indeterminate. Значение свойства IsChecked определяет состояние CheckBox, а состояние последнего определяет, что появляется в поле.

В приведенной ниже таблице перечислены возможные значения IsChecked, соответствующие состояния CheckBox и представление CheckBox.

Значение IsChecked Состояние CheckBox Вид CheckBox
true Checked Содержит X.
false Unchecked Пусто.
null Indeterminate Содержит кружок.

Для указания представления элемента управления, когда он находится в определенном состоянии, используйте объекты VisualState. Объект VisualState содержит класс Setter или Storyboard, меняющий представление элементов в классе ControlTemplate. Когда элемент управления переходит в состояние, указанное в свойстве VisualState.Name, применяются изменения свойств в Setter или Storyboard. Когда элемент управления выходит из этого состояния, изменения удаляются. Мы добавляем объекты VisualState к объектам VisualStateGroup. Мы добавляем объекты VisualStateGroup к подключенному свойству VisualStateManager.VisualStateGroups, установленному на корневом элементе FrameworkElement шаблона ControlTemplate.

Приведенный XAML-код показывает объекты VisualState для состояний Checked, Unchecked и Indeterminate. Данный пример задает присоединенное свойство VisualStateManager.VisualStateGroups для Border, который является корневым элементом ControlTemplate. VisualStateChecked указывает, что значение Opacityпути с именем CheckGlyph (как показано в предыдущем примере) равно 1. VisualStateIndeterminate указывает, что значение Opacity имени эллипсаIndeterminateGlyph равно 1. VisualStateUnchecked не имеет метода задания или раскадровки, поэтому элемент CheckBox возвращает свой внешний вид по умолчанию.

<ControlTemplate x:Key="CheckBoxTemplate1" TargetType="CheckBox">
    <Border BorderBrush="{TemplateBinding BorderBrush}"
            BorderThickness="{TemplateBinding BorderThickness}"
            Background="{TemplateBinding Background}">

        <VisualStateManager.VisualStateGroups>
            <VisualStateGroup x:Name="CheckStates">
                <VisualState x:Name="Checked">
                    <VisualState.Setters>
                        <Setter Target="CheckGlyph.Opacity" Value="1"/>
                    </VisualState.Setters>
                    <!-- This Storyboard is equivalent to the Setter. -->
                    <!--<Storyboard>
                        <DoubleAnimation Duration="0" To="1"
                         Storyboard.TargetName="CheckGlyph" Storyboard.TargetProperty="Opacity"/>
                    </Storyboard>-->
                </VisualState>
                <VisualState x:Name="Unchecked"/>
                <VisualState x:Name="Indeterminate">
                    <VisualState.Setters>
                        <Setter Target="IndeterminateGlyph.Opacity" Value="1"/>
                    </VisualState.Setters>
                    <!-- This Storyboard is equivalent to the Setter. -->
                    <!--<Storyboard>
                        <DoubleAnimation Duration="0" To="1"
                         Storyboard.TargetName="IndeterminateGlyph" Storyboard.TargetProperty="Opacity"/>
                    </Storyboard>-->
                </VisualState>
            </VisualStateGroup>
        </VisualStateManager.VisualStateGroups>

        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="*"/>
                <RowDefinition Height="25"/>
            </Grid.RowDefinitions>
            <Rectangle x:Name="NormalRectangle" Fill="Transparent" Height="20" Width="20"
                       Stroke="{ThemeResource SystemControlForegroundBaseMediumHighBrush}"
                       StrokeThickness="{ThemeResource CheckBoxBorderThemeThickness}"
                       UseLayoutRounding="False"/>
            <!-- Create an X to indicate that the CheckBox is selected. -->
            <Path x:Name="CheckGlyph"
                  Data="M103,240 L111,240 119,248 127,240 135,240 123,252 135,264 127,264 119,257 111,264 103,264 114,252 z"
                  Fill="{ThemeResource CheckBoxForegroundThemeBrush}"
                  FlowDirection="LeftToRight"
                  Height="14" Width="16" Opacity="0" Stretch="Fill"/>
            <Ellipse x:Name="IndeterminateGlyph"
                     Fill="{ThemeResource CheckBoxForegroundThemeBrush}"
                     Height="8" Width="8" Opacity="0" UseLayoutRounding="False" />
            <ContentPresenter x:Name="ContentPresenter"
                              ContentTemplate="{TemplateBinding ContentTemplate}"
                              Content="{TemplateBinding Content}"
                              Margin="{TemplateBinding Padding}" Grid.Row="1"
                              HorizontalAlignment="Center"
                              VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
        </Grid>
    </Border>
</ControlTemplate>

Чтобы лучше понять, как работают объекты VisualState, давайте рассмотрим, что происходит, когда CheckBox переходит из состояния Unchecked в состояние Checked, затем в состояние Indeterminate и обратно в состояние Unchecked. Вот эти переходы.

Смена состояния Что происходит Представление CheckBox по завершении смены состояния
С Unchecked на Checked. Применяется значение CheckedSettervisualState, поэтому значение OpacityCheckGlyph равно 1. Отображается X.
С Checked на Indeterminate. Применяется значение IndeterminateSettervisualState, поэтому значение OpacityIndeterminateGlyph равно 1. Значение CheckedSettervisualState удаляется, поэтому значение OpacityCheckGlyph равно 0. Отображается круг.
С Indeterminate на Unchecked. Значение IndeterminateSettervisualState удаляется, поэтому значение OpacityIndeterminateGlyph равно 0. Не отображается ничего.

  Подробнее о том, как создавать визуальные состояния элементов управления, в частности о том, как использовать класс Storyboard и типы анимации см. в разделе Раскадрованные анимации для визуальных состояний.

Используйте средства для упрощения работы с темами

Чтобы быстро применить темы к своим элементам управления, щелкните элемент управления правой кнопкой мыши в структуре документа Microsoft Visual Studio XAML и выберите команду Изменить тему или Изменить стиль (в зависимости от элемента управления). Затем можно применить существующую тему, выбрав команду Применить ресурс, или определить новую командой Создать пустой.

Элементы управления и специальные возможности

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

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

Когда вы создаете совершенно новый пользовательский элемент управления, порой бывает необходимо создать помимо этого новый одноранговый элемент автоматизации. Дополнительную информацию см. в разделе Настраиваемые одноранговые элементы автоматизации.

Дополнительные сведения о стандартном шаблоне элемента управления

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

Ресурсы тем в шаблонах элементов управления

В некоторых атрибутах в примерах кода XAML вы могли заметить ссылки на ресурсы, которые используют расширение разметки {ThemeResource}. Данная технология позволяет одному шаблону элемента управления использовать разнообразные ресурсы в зависимости от того, какая из тем активна на текущий момент. Это особенно важно для кистей и цветов, поскольку основная цель тем — предоставить пользователям возможность выбора темной или светлой темы либо темы "Высокая контрастность" в применении к системе в целом. Приложения, которые используют систему на базе ресурсов XAML, могут использовать набор ресурсов, соответствующий определенной теме. Выбор темы в пользовательском интерфейсе приложения будет отражать выбор пользователем темы для всей системы в целом.

Получение примера кода