Windows Presentation Foundation(WPF)样式和模板化是指一套功能,使开发人员和设计人员能够为其产品创建具有视觉吸引力的效果和一致的外观。 自定义应用的外观时,需要一个强大的样式和模板化模型,用于在应用内和应用之间维护和共享外观。 WPF 提供该模型。

WPF 样式模型的另一个功能是表示和逻辑分离。 设计器只需使用 XAML 即可处理应用的外观,同时开发人员使用 C# 或 Visual Basic 处理编程逻辑。

本概述重点介绍应用的样式设置和模板化方面,不讨论任何数据绑定概念。 有关数据绑定的信息,请参阅 数据绑定概述。

了解资源非常重要,这些资源允许重复使用样式和模板。 有关资源的详细信息,请参阅 XAML 资源的概述。

示例

如下图所示,本概述中提供的示例代码基于 简单的照片浏览应用程序。

这个简单的照片示例使用样式和模板化来创建具有视觉吸引力的用户体验。 该示例具有两个 TextBlock 元素和一个绑定到图像列表的 ListBox 控件。

有关完整示例,请参阅样式设置和模板化示例简介。

风格

可以将 Style 视为将一组属性值应用于多个元素的便捷方法。 可以在派生自 FrameworkElement 或 FrameworkContentElement(如 Window 或 Button)的任何元素上使用样式。

在 XAML 文件的 Resources 部分,声明样式的最常见方法是将其作为资源。 由于样式是资源,因此它们遵循适用于所有资源的相同范围规则。 简单来说,您声明样式的位置会影响该样式可以应用的位置。 例如,如果在应用定义 XAML 文件的根元素中声明样式,则可以在应用中的任意位置使用该样式。

例如,以下 XAML 代码为 TextBlock声明两种样式,一个样式自动应用于所有 TextBlock 元素,另一个必须显式引用。

下面是上面声明样式的一个使用示例。

My Pictures

Check out my new pictures!

有关详细信息,请参阅 为控件创建样式。

ControlTemplate

在 WPF 中,控件 ControlTemplate 定义控件的外观。 可以通过定义新的 ControlTemplate 并将其分配给控件来更改控件的结构和外观。 在许多情况下,模板提供了足够的灵活性,因此无需编写自己的自定义控件。

每个控件都有一个分配给 Control.Template 属性的默认模板。 该模板将控件的视觉呈现与控件的功能连接起来。 由于在 XAML 中定义模板,因此无需编写任何代码即可更改控件的外观。 每个模板专为特定控件设计,例如 Button。

通常,在 XAML 文件的 Resources 节上将模板声明为资源。 与所有资源一样,范围规则适用。

控件模板比样式更复杂得多。 这是因为控件模板重写了整个控件的视觉外观,而样式只是将属性更改应用于现有控件。 但是,由于通过设置 control.Template 属性来应用控件的模板,因此可以使用样式来定义或设置模板。

设计器通常允许创建现有模板的副本并对其进行修改。 例如,在 Visual Studio WPF 设计器中,选择 CheckBox 控件,然后右键单击并选择 编辑模板>创建副本。 此命令生成一个 样式,该样式定义了模板。

此示例使用 Trigger 设置属性值,但请注意,Trigger 类还具有允许触发器执行操作的 EnterActions 和 ExitActions 属性。

请注意,MaxHeight 的 ListBoxItem 属性设置为 75。 在下图中,第三项是被选中的项。

EventTrigger 和情节提要

另一种类型的触发器是 EventTrigger,它根据事件的出现情况启动一组操作。 例如,以下 EventTrigger 对象指定当鼠标指针进入 ListBoxItem 时,MaxHeight 属性在 90 秒的时间内动画化为值 0.2。 当鼠标移开该项时,该属性将在 1 秒内恢复到原始值。 请注意,没有必要为 To 动画指定 MouseLeave 值。 这是因为动画能够跟踪原始值。

Duration="0:0:0.2"

Storyboard.TargetProperty="MaxHeight"

To="90" />

Duration="0:0:1"

Storyboard.TargetProperty="MaxHeight" />

有关详细信息,请参阅 故事板概述。

在下图中,鼠标指向第三项。

MultiTrigger、DataTrigger 和 MultiDataTrigger

除了 Trigger 和 EventTrigger,还有其他类型的触发器。

MultiTrigger 允许你根据多个条件设置属性值。 当条件的属性绑定数据时,可以使用 DataTrigger 和 MultiDataTrigger。

视觉状态

控件始终处于特定的 状态。 例如,当鼠标在控件表面上移动时,该控件被视为处于 MouseOver的常见状态。 没有特定状态的控件被视为处于常见 Normal 状态。 州分为组,前面提到的州是州组 CommonStates的一部分。 大多数控件都有两个状态组:CommonStates 和 FocusStates。 应用于控件的每个状态组中,控件始终处于每个组的一个状态,例如 CommonStates.MouseOver 和 FocusStates.Unfocused。 但是,控件不能在同一组中处于两个不同的状态,例如 CommonStates.Normal 和 CommonStates.Disabled。 下面是大多数控件识别和使用的状态表。

VisualState 名称

VisualStateGroup 名称

DESCRIPTION

Normal

CommonStates

默认状态。

MouseOver

CommonStates

鼠标指针悬停在控件上。

Pressed

CommonStates

已按下控件。

Disabled

CommonStates

控件已禁用。

Focused

FocusStates

控件有焦点。

Unfocused

FocusStates

控件没有焦点。

通过在控件模板的根元素上定义 System.Windows.VisualStateManager,可以在控件进入特定状态时触发动画。

VisualStateManager 声明要监视的 VisualStateGroup 和 VisualState 的组合。 当控件进入监视状态时,将启动由 VisualStateManager 定义的动画。

例如,以下 XAML 代码监视 CommonStates.MouseOver 状态,以对名为 backgroundElement的元素的填充颜色进行动画处理。 当控件返回到 CommonStates.Normal 状态时,将还原名为 backgroundElement 的元素的填充颜色。

Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)"

To="{TemplateBinding Background}"

Duration="0:0:0.3"/>

Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)"

To="Yellow"

Duration="0:0:0.3"/>

...

有关分镜头脚本的详细信息,请参阅 分镜头脚本概述。

共享资源和主题

典型的 WPF 应用可能有多个在整个应用中应用的 UI 资源。 统一而言,可以将这组资源视为应用的主题。 WPF 支持将 UI 资源打包为主题,这是通过使用封装在 ResourceDictionary 类中的资源字典实现的。

WPF 主题通过使用 WPF 公开的样式设置和模板化机制来定义,以便自定义任何元素的视觉对象。

WPF 主题资源存储在嵌入的资源字典中。 这些资源字典必须嵌入到已签名程序集中,并且可以嵌入到代码本身所在的程序集或并行程序集中。 对于包含 WPF 控件的程序集 PresentationFramework.dll,主题资源位于一系列并行程序集内。

在搜索元素样式时,主题将成为查找的最后一个位置。 通常,搜索首先通过浏览元素树来搜索适当的资源,然后查找应用资源集合,最后查询系统。 这样,应用开发人员就有机会在达到主题之前重新定义树级或应用级别的任何对象的样式。

可以将资源字典定义为单个文件,以便跨多个应用重复使用主题。 还可以通过定义多个资源字典来创建可交换的主题,这些字典提供相同类型的资源,但具有不同的值。 建议在应用级别重新定义这些样式或其他资源,以便对应用进行外观处理。

若要跨应用共享一组资源(包括样式和模板),可以创建 XAML 文件并定义包含对 ResourceDictionary 文件的引用的 shared.xaml。

它是 shared.xaml 的共享,用于定义包含一组样式和画笔资源的 ResourceDictionary,从而使应用中的控件具有一致的外观。

有关详细信息,请参阅 合并资源字典。

如果要为自定义控件创建主题,请参阅控件创作概述的“在主题级别定义资源”部分。

另请参阅

WPF 中的 Pack URI

如何:查找由 ControlTemplate 生成的元素

查找由 DataTemplate 生成的元素