控件模板

可以通过在 XAML 框架中创建控件模板来自定义控件的视觉结构和视觉行为。 控件具有许多属性,如 BackgroundForeground FontFamily,你可以将其设置为指定控件外观的不同方面。 但是,通过设置这些属性可以做出的更改受到限制。 可以使用 ControlTemplate 类创建模板来指定其他自定义项。 下面介绍如何创建 ControlTemplate 以自定义 CheckBox 控件的外观

重要 APIControlTemplate 类Control.Template 属性

自定义控件模板示例

默认情况下,CheckBox 控件将其内容(CheckBox 旁边的字符串或对象)放在选定框右侧,复选标记指示用户选择了 CheckBox 这些特征表示 CheckBox可视结构和视觉行为。

下面是使用状态和UncheckedIndeterminateChecked状态中显示的默认 ControlTemplate 的 CheckBox

默认复选框模板

可以通过为 CheckBox 创建 ControlTemplate 来更改这些特征。 例如,如果希望复选框的内容位于选择框下方,并且希望使用 X 指示用户选择了复选框。 在 CheckBox 的 ControlTemplate 中指定这些特征

若要将自定义模板与控件一起使用,请将 ControlTemplate 分配给控件的 Template 属性。 下面是使用称为 CheckBoxTemplate1ControlTemplateCheckBox。 我们在下一节介绍 ControlTemplate 的 Extensible Application Markup Language (XAML)。

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

下面是应用模板后此 CheckBox 的外观UncheckedCheckedIndeterminate状态。

自定义复选框模板

指定控件的可视结构

创建 ControlTemplate 时,将 FrameworkElement 对象合并为生成单个控件。 ControlTemplate 必须只有一个 FrameworkElement 作为其根元素。 根元素通常包含其他 FrameworkElement 对象。 对象组合构成控件的可视结构。

此 XAML 为 CheckBox 创建 ControlTemplate,该复选框指定控件的内容位于选择框下方。 根元素是 边框。 该示例指定用于创建 X 的路径,该 X 指示用户选择了 CheckBox,以及指示不确定状态的椭圆。 请注意,Opacity 在 PathEllipse设置为 0,这样默认情况下,两者都不会出现。

TemplateBinding 是一种特殊的绑定,将一个控件模板中的属性值链接到模板控件上的某个其他公开的属性的值。 TemplateBinding 只能在 XAML 中的 ControlTemplate 定义中使用。 有关详细信息,请参阅 TemplateBinding 标记扩展

注意

从 Windows 10 版本 1809 (SDK 17763) 开始,可以在使用 TemplateBinding 的位置使用 x:Bind 标记扩展。 有关详细信息,请参阅 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 控件有 3 个检查状态:CheckedUncheckedIndeterminate。 IsChecked 属性的值确定 CheckBox 的状态,其状态确定框中显示的内容。

下表列出了 IsChecked可能值、CheckBox相应状态以及 CheckBox 的外观。

IsChecked CheckBox 状态 CheckBox 外观
true Checked 包含“X”。
false Unchecked 空白。
null Indeterminate 包含一个圆。

使用 VisualState 对象指定控件处于特定状态时的外观。 VisualState 包含一个 SetterStoryboard,用于更改 ControlTemplate元素的外观。 当控件进入 VisualState.Name 属性指定的状态时,将应用 SetterStoryboard 中的属性更改。 当控件退出状态时,将删除更改。 你可以将 VisualState 对象添加到 VisualStateGroup 对象。 还可以将 VisualStateGroup 对象添加到 VisualStateManager.VisualStateGroups 附加属性,这些对象在 ControlTemplate 的根 FrameworkElement 上设置。

以下 XAML 介绍在 CheckedUncheckedIndeterminate 状态下的 VisualState 对象。 该示例在 Border 上设置 VisualStateManager.VisualStateGroups 附加属性,它是 ControlTemplate 的根元素。 Checked VisualState 指定名为 CheckGlyphPath(已在前面的示例中介绍)的 Opacity 为 1。 Indeterminate VisualState 指定名为 IndeterminateGlyphEllipseOpacity 为 1。 Unchecked VisualState 没有 SetterStoryboard,因此 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 对象的工作原理,请考虑 CheckBoxUnchecked状态到Checked状态、Indeterminate状态,然后返回到Unchecked状态时会发生什么情况。 下面是转换。

状态转换 发生的更改 切换完成后的 CheckBox 外观
UncheckedChecked Checked VisualStateSetter 值已应用,因此 CheckGlyphOpacity 为 1。 将显示 X。
CheckedIndeterminate Indeterminate VisualStateSetter 值已应用,因此 IndeterminateGlyphOpacity 为 1。 Checked VisualStateSetter 值已删除,因此 CheckGlyphOpacity 为 0。 将显示一个圆。
IndeterminateUnchecked Indeterminate VisualStateSetter 值已删除,因此 IndeterminateGlyphOpacity 为 0。 不显示任何内容。

  有关如何为控件创建视觉状态的详细信息,特别是如何使用 Storyboard 类和动画类型,请参阅视觉状态的情节提要动画。

使用工具轻松处理主题

将主题应用于控件的快速方法是右键单击 Visual Studio 文档大纲 Microsoft上的控件,然后选择“编辑主题”或“编辑样式(具体取决于您右键单击的控件)。 然后,可以通过选择“应用资源来应用现有主题,也可以通过选择“创建空来定义一个新主题。

控件和辅助功能

为控件创建新模板时,除了可能更改控件的行为和视觉外观外,还可以更改控件将自身表示为辅助功能框架的方式。 Windows 应用支持 Microsoft UI 自动化框架用于辅助功能。 所有默认控件及其模板都支持适用于控件用途和函数的常见UI 自动化控件类型和模式。 这些控件类型和模式由UI 自动化客户端(如辅助技术)解释,这使控件可以作为较大辅助应用 UI 的一部分进行访问。

为了分离基本控制逻辑,并且为了满足UI 自动化的一些体系结构要求,控件类在单独的类(自动化对等类)中包括其辅助功能支持。 自动化对等有时与控件模板交互,因为对等方希望模板中存在某些命名部件,因此可以启用辅助技术来调用按钮操作等功能。

创建全新的自定义控件时,有时还希望创建新的自动化对等方来配合它。 有关详细信息,请参阅 自定义自动化对等方

详细了解控件的默认模板

记录 XAML 控件样式和模板的主题显示你是否使用了前面介绍的 “编辑主题 ”或 “编辑样式 ”技术时所用的相同起始 XAML 的摘录。 每个主题列出了视觉状态的名称、使用的主题资源以及包含模板的样式的完整 XAML。 如果已开始修改模板并想要查看原始模板的外观,或者验证新模板是否具有所有必需的命名视觉状态,这些主题可能很有用。

控件模板中的主题资源

对于 XAML 示例中的某些属性,你可能已注意到使用 {ThemeResource} 标记扩展的资源引用。 这是一种技术,使单个控件模板能够使用资源,这些资源可以是不同的值,具体取决于当前处于活动状态的主题。 对于画笔和颜色来说,这尤其重要,因为主题的主要目的是让用户选择是想要应用于系统整体的深色、浅色还是高对比度主题。 使用 XAML 资源系统的应用可以使用适用于该主题的资源集,以便应用的 UI 中的主题选项反映用户的全系统主题选择。

获取示例代码