控件模板

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

重要 APIControlTemplate 类Control.Template 属性

自定义控件模板示例

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

下面是一个使用默认 ControlTemplateCheckBox,显示在 UncheckedCheckedIndeterminate 状态中。

默认复选框模板

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

若要对控件使用自定义模板,请将 ControlTemplate 分配给控件的 Template 属性。 下面是使用名为 ControlTemplateCheckBoxTemplate1。 我们将在下一部分显示 ControlTemplate 的可扩展应用程序标记语言(XAML)。

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

应用模板后,以下是 CheckBoxUncheckedCheckedIndeterminate 状态下的外观。

自定义复选框模板

指定控件的可视结构

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

此 XAML 为 CheckBox 创建 ControlTemplate,指定控件的内容位于选择框下方。 根元素是 边框。 该示例指定了一个 路径,用于创建一个 X,表示用户选择了 复选框,以及一个 椭圆,表示不确定状态。 请注意, OpacityPathEllipse 上设置为 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”。
Unchecked 空白。
Indeterminate 包含一个圆。

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

此 XAML 显示 Checked 状态的 Indeterminate 对象。 该示例在 Border上设置了 VisualStateManager.VisualStateGroups 附加属性,该属性是 ControlTemplate的根元素。 Checked VisualState 指定名为 路径CheckGlyph(上一示例中所示)为 1。 Indeterminate VisualState 指定名为 椭圆IndeterminateGlyph 为 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 Setter 的值应用于 CheckedVisualState,因此 CheckGlyph 为 1。 将显示 X。
CheckedIndeterminate Setter 的值应用于 IndeterminateVisualState,因此 IndeterminateGlyph 为 1。 VisualStateCheckedSetter 值被移除,因此 CheckGlyph不透明度 为 0。 将显示一个圆。
IndeterminateUnchecked Indeterminate VisualStateSetter 值已被删除,因此 IndeterminateGlyph不透明度 为 0。 不显示任何内容。

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

使用工具轻松处理主题

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

控件和辅助功能

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

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

创建全新的自定义控件时,有时还希望创建新的自动化同级对象与之匹配。 有关详细信息,请参阅 自定义自动化伙伴

详细了解控件的默认模板

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

控件模板中的主题资源

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

获取示例代码