控件模板Control templates

通过在 XAML 框架中创建控件模板,你可以自定义控件的可视结构和可视行为。You can customize a control's visual structure and visual behavior by creating a control template in the XAML framework. 控件有多个属性,如 BackgroundForeground 以及 FontFamily,可以设置这些属性以指定控件外观的多个方面。Controls have many properties, such as Background, Foreground, and FontFamily, that you can set to specify different aspects of the control's appearance. 但是可以通过设置这些属性所做的更改有限。But the changes that you can make by setting these properties are limited. 你可以通过使用 ControlTemplate 类创建模板来指定其他自定义。You can specify additional customizations by creating a template using the ControlTemplate class. 我们在此处介绍如何创建 ControlTemplate 以自定义 CheckBox 控件的外观。Here, we show you how to create a ControlTemplate to customize the appearance of a CheckBox control.

重要的 APIControlTemplate 类Control.Template 属性Important APIs: ControlTemplate class, Control.Template property

自定义控件模板示例Custom control template example

在默认情况下,CheckBox 控件将其内容(字符串或 CheckBox 旁的对象)放在选择框的右侧,并使用复选标记来表示用户已选中 CheckBoxBy default, a CheckBox control puts its content (the string or object next to the CheckBox) to the right of the selection box, and a check mark indicates that a user selected the CheckBox. 这些特性表示 CheckBox 的可视结构和可视行为。These characteristics represent the visual structure and visual behavior of the CheckBox.

下面是分别在 UncheckedCheckedIndeterminate 状态下使用默认 ControlTemplateCheckBoxHere's a CheckBox using the default ControlTemplate shown in the Unchecked, Checked, and Indeterminate states.

默认 CheckBox 模板

你可以通过为 CheckBox 创建 ControlTemplate 来更改这些特性。You can change these characteristics by creating a ControlTemplate for the CheckBox. 例如,如果你想要让复选框的内容显示在选择框下方,并且你想要用 X 来表示用户已选中复选框。For example, if you want the content of the check box to be below the selection box, and you want to use an X to indicate that a user selected the check box. 你可以在 CheckBoxControlTemplate 中指定这些特性。You specify these characteristics in the ControlTemplate of the CheckBox.

若要将自定义模板与控件一起使用,请将 ControlTemplate 分配给控件的 Template 属性。To use a custom template with a control, assign the ControlTemplate to the Template property of the control. 下面是使用称为 CheckBoxTemplate1ControlTemplateCheckBoxHere's a CheckBox using a ControlTemplate called CheckBoxTemplate1. 我们在下一节介绍 ControlTemplate 的 Extensible Application Markup Language (XAML)。We show the Extensible Application Markup Language (XAML) for the ControlTemplate in the next section.

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

下面是在应用模板后,CheckBoxUncheckedCheckedIndeterminate 状态下的外观。Here's how this CheckBox looks in the Unchecked, Checked, and Indeterminate states after we apply our template.

自定义 CheckBox 模板

指定控件的可视结构Specify the visual structure of a control

当你创建 ControlTemplate 时,结合 FrameworkElement 对象来生成一个单一的控件。When you create a ControlTemplate, you combine FrameworkElement objects to build a single control. ControlTemplate 只能有一个 FrameworkElement 作为其根元素。A ControlTemplate must have only one FrameworkElement as its root element. 该根元素通常包含其他 FrameworkElement 对象。The root element usually contains other FrameworkElement objects. 这些对象的组合组成控件的可视结构。The combination of objects makes up the control's visual structure.

此 XAML 为 CheckBox 创建了 ControlTemplate,可指定控件的内容显示在选择框的下方。This XAML creates a ControlTemplate for a CheckBox that specifies that the content of the control is below the selection box. 根元素为 BorderThe root element is a Border. 该示例指定 Path 来创建 X,表示用户已选定 CheckBox,并用 Ellipse 表示不确定状态。The example specifies a Path to create an X that indicates that a user selected the CheckBox, and an Ellipse that indicates an indeterminate state. 请注意,OpacityPathEllipse 上均设置为 0,因此在默认情况下,两者都不会显示。Note that the Opacity is set to 0 on the Path and the Ellipse so that by default, neither appear.

TemplateBinding 是一种特殊的绑定,将一个控件模板中的属性值链接到模板控件上的某个其他公开的属性的值。A TemplateBinding is a special binding that links the value of a property in a control template to the value of some other exposed property on the templated control. TemplateBinding 只能在 XAML 中的 ControlTemplate 定义中使用。TemplateBinding can only be used within a ControlTemplate definition in XAML. 有关详细信息,请参阅 TemplateBinding 标记扩展See TemplateBinding markup extension for more info.

备注

从 Windows 10 版本 1809 (SDK 17763) 开始,可以在使用 TemplateBinding 的位置使用 x:Bind 标记扩展。Starting with Windows 10, version 1809 (SDK 17763), you can use x:Bind markup extensions in places you use TemplateBinding. 有关详细信息,请参阅 TemplateBinding 标记扩展See TemplateBinding markup extension for more info.

<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>

指定控件的可视行为Specify the visual behavior of a control

可视行为指定控件在确定状态下的外观。A visual behavior specifies the appearance of a control when it is in a certain state. CheckBox 控件具有 3 种复选状态:CheckedUncheckedIndeterminateThe CheckBox control has 3 check states: Checked, Unchecked, and Indeterminate. IsChecked 属性的值确定 CheckBox 的状态,其状态确定框中显示的内容。The value of the IsChecked property determines the state of the CheckBox, and its state determines what appears in the box.

下表列出了 IsChecked 的可能值、CheckBox 的相应状态,以及 CheckBox 的外观。This table lists the possible values of IsChecked, the corresponding states of the CheckBox, and the appearance of the CheckBox.

IsCheckedIsChecked value CheckBox 状态CheckBox state CheckBox 外观CheckBox appearance
truetrue Checked 包含“X”。Contains an "X".
falsefalse Unchecked 空白。Empty.
nullnull Indeterminate 包含一个圆形。Contains a circle.

使用 VisualState 对象可指定控件在某种状态下的外观。You specify the appearance of a control when it is in a certain state by using VisualState objects. VisualState 包含可更改 ControlTemplate 中元素外观的 SetterStoryboardA VisualState contains a Setter or Storyboard that changes the appearance of the elements in the ControlTemplate. 当控件进入 VisualState.Name 属性指定的状态时,将应用 SetterStoryboard 中的属性更改。When the control enters the state that the VisualState.Name property specifies, the property changes in the Setter or Storyboard are applied. 当控件退出该状态时,这些更改将会删除。When the control exits the state, the changes are removed. 你可以将 VisualState 对象添加到 VisualStateGroup 对象。You add VisualState objects to VisualStateGroup objects. 还可以将 VisualStateGroup 对象添加到 VisualStateManager.VisualStateGroups 附加属性,这些对象在 ControlTemplate 的根 FrameworkElement 上设置。You add VisualStateGroup objects to the VisualStateManager.VisualStateGroups attached property, which you set on the root FrameworkElement of the ControlTemplate.

以下 XAML 介绍在 CheckedUncheckedIndeterminate 状态下的 VisualState 对象。This XAML shows the VisualState objects for the Checked, Unchecked, and Indeterminate states. 该示例在 Border 上设置 VisualStateManager.VisualStateGroups 附加属性,它是 ControlTemplate 的根元素。The example sets the VisualStateManager.VisualStateGroups attached property on the Border, which is the root element of the ControlTemplate. Checked VisualState 指定名为 CheckGlyphPath(已在前面的示例中介绍)的 Opacity 为 1。The Checked VisualState specifies that the Opacity of the Path named CheckGlyph (which we show in the previous example) is 1. Indeterminate VisualState 指定名为 IndeterminateGlyphEllipseOpacity 为 1。The Indeterminate VisualState specifies that the Opacity of the Ellipse named IndeterminateGlyph is 1. Unchecked VisualState 没有 SetterStoryboard,因此 CheckBox 将返回到其默认外观。The Unchecked VisualState has no Setter or Storyboard, so the CheckBox returns to its default appearance.

<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 对象的工作原理,请考虑当 CheckBoxUnchecked 状态切换到 Checked 状态,然后切换到 Indeterminate 状态,然后又恢复为 Unchecked 状态时,会发生什么。To better understand how VisualState objects work, consider what happens when the CheckBox goes from the Unchecked state to the Checked state, then to the Indeterminate state, and then back to the Unchecked state. 下表介绍了这些转换。Here are the transitions.

状态转换State transition 引发的结果What happens 转换完成时的 CheckBox 外观CheckBox appearance when the transition completes
UncheckedCheckedFrom Unchecked to Checked. 应用 Checked VisualStateSetter 值,因此 CheckGlyphOpacity 为 1。The Setter value of the Checked VisualState is applied, so the Opacity of CheckGlyph is 1. 显示 X。An X is displayed.
CheckedIndeterminateFrom Checked to Indeterminate. 应用 Indeterminate VisualStateSetter 值,因此 IndeterminateGlyphOpacity 为 1。The Setter value of the Indeterminate VisualState is applied, so the Opacity of IndeterminateGlyph is 1. 删除 Checked VisualStateSetter 值,因此 CheckGlyphOpacity 为 0。The Setter value of the Checked VisualState is removed, so the Opacity of CheckGlyph is 0. 显示一个圆形。A circle is displayed.
IndeterminateUncheckedFrom Indeterminate to Unchecked. 删除 Indeterminate VisualStateSetter 值,因此 IndeterminateGlyphOpacity 为 0。The Setter value of the Indeterminate VisualState is removed, so the Opacity of IndeterminateGlyph is 0. 不显示任何符号。Nothing is displayed.

  有关如何创建控件的视觉状态(尤其是如何使用 Storyboard 类和动画类型)的详细信息,请参阅视觉状态的情节提要动画For more info about how to create visual states for controls, and in particular how to use the Storyboard class and the animation types, see Storyboarded animations for visual states.

使用工具轻松处理主题Use tools to work with themes easily

将主题应用到控件的一种快捷方式是,在 Microsoft Visual Studio XAML“文档大纲” 上右键单击控件,然后选择“编辑主题” 或“编辑样式” (具体取决于你所右键单击的控件)。A fast way to apply themes to your controls is to right-click on a control on the Microsoft Visual Studio Document Outline and select Edit Theme or Edit Style (depending on the control you are right-clicking on). 然后,通过选择“应用资源” 来应用现有主题,或通过选择“创建空项” 来定义一个新主题。You can then apply an existing theme by selecting Apply Resource or define a new one by selecting Create Empty.

控件和辅助功能Controls and accessibility

当为控件创建新模板时,除了可能会更改控件的行为和视觉外观外,还可能会更改控件自行代表辅助功能框架的方式。When you create a new template for a control, in addition to possibly changing the control's behavior and visual appearance, you might also be changing how the control represents itself to accessibility frameworks. 通用 Windows 平台 (UWP) 支持 Microsoft UI 自动化框架用于辅助功能。The Universal Windows Platform (UWP) supports the Microsoft UI Automation framework for accessibility. 所有默认控件及其模板都支持适用于控件的用途和功能的常见 UI 自动化控件类型和模式。All of the default controls and their templates have support for common UI Automation control types and patterns that are appropriate for the control's purpose and function. 这些控件类型和模式由 UI 自动化客户端(如辅助技术)进行解释,这样允许控件作为较大辅助应用 UI 的一部分进行访问。These control types and patterns are interpreted by UI Automation clients such as assistive technologies, and this enables a control to be accessible as a part of a larger accessible app UI.

若要分离基本控件逻辑以及符合 UI 自动化的某些体系结构要求,控件类在独立类(自动化对等)中包含辅助功能支持。To separate the basic control logic and also to satisfy some of the architectural requirements of UI Automation, control classes include their accessibility support in a separate class, an automation peer. 有时自动化对等会与控件模板有交互,因为对等预期某些命名部件存在于模板中,以便可能会使用诸如允许辅助技术调用按钮操作的功能。The automation peers sometimes have interactions with the control templates because the peers expect certain named parts to exist in the templates, so that functionality such as enabling assistive technologies to invoke actions of buttons is possible.

创建全新的自定义控件时,有时还希望随之一起新建自动化对等。When you create a completely new custom control, you sometimes also will want to create a new automation peer to go along with it. 有关详细信息,请参阅自定义的自动化对等For more info, see Custom automation peers.

了解有关控件默认模板的详细信息Learn more about a control's default template

记录了 XAML 控件样式和模板的主题向你显示的起始 XAML 摘录与使用之前介绍的“编辑主题” 或“编辑样式” 技术时看到的相同。The topics that document the styles and templates for XAML controls show you excerpts of the same starting XAML you'd see if you used the Edit Theme or Edit Style techniques explained previously. 每个主题都将列出视觉状态的名称、使用的主题资源,以及包含该模板的样式的完整 XAML。Each topic lists the names of the visual states, the theme resources used, and the full XAML for the style that contains the template. 如果你已开始修改模板并要查看原始模板的外观,或者想要验证你的新模板是否具有所有所需的命名视觉状态,这些主题将是非常有用的指南。The topics can be useful guidance if you've already started modifying a template and want to see what the original template looked like, or to verify that your new template has all of the required named visual states.

控件模板中的主题资源Theme resources in control templates

对于 XAML 模板中的某些属性,你可能已注意到使用 {ThemeResource} 标记扩展的资源引用。For some of the attributes in the XAML examples, you may have noticed resource references that use the {ThemeResource} markup extension. 这是一种可使单个控件模板使用资源的技术,这些资源可能采用不同的值,具体取决于当前处于活动状态的主题。This is a technique that enables a single control template to use resources that can be different values depending on which theme is currently active. 这对于画笔和颜色尤其重要,因为主题的主要目的是使用户选择应用于整个系统的是深色主题、浅色主题,还是高对比度主题。This is particularly important for brushes and colors, because the main purpose of the themes is to enable users to choose whether they want a dark, light, or high contrast theme applied to the system overall. 使用 XAML 资源系统的应用可以使用适合该主题的资源集,以便应用 UI 中的主题选择可以反映用户的整个系统的主题选择。Apps that use the XAML resource system can use a resource set that's appropriate for that theme, so that the theme choices in an app's UI are reflective of the user's systemwide theme choice.

获取示例代码Get the sample code