Skip to Content
Week 08Day 1 - 样式体系

Day 1 - 样式体系

建议用时:210-240 分钟

你将学会什么

  • 知道 Resources 是可复用的值。
  • 知道 Styles 是可复用的外观规则。
  • 会在 App.axaml 里定义全局颜色资源。
  • 会在 App.axaml 里定义全局按钮和标题样式。
  • 会用 Classes 给控件套用指定样式。
  • 会判断什么时候放全局,什么时候放当前页面。

本页只讲样式体系基础:资源、样式、选择器、样式类、作用范围。DataTemplateControlTemplateUserControl 会在后面几天单独讲。

本页固定顺序

  1. 先学第一部分:弄懂今天最小、最重要的知识,并运行短例子。
  2. 再学第二部分:把刚学的知识组合成一个完整例子。
  3. 然后做第三部分:自己跟着敲,再完成重复训练和每日小测。
  4. 最后做第四部分:先独立完成作业,再用完整答案检查。

学习衔接

上一页学习的是“复盘与巩固”,今天继续学习“样式体系”。先使用上一页已经会的写法,再只增加今天这个新知识点;如果前置内容还不能独立敲出,先回上一页复习,不要硬跳。

今天的最低通过线

第一次学习不要求背完整页。完成下面 3 项,就可以继续:

  • 能用自己的话说明“样式体系”解决什么问题。
  • 把第一部分的短例子亲手敲完,并确认每个例子都能运行。
  • 不看完整答案完成第三部分至少前 3 个例子,再主动改一个值观察结果。

第一部分:先学原理和最小知识

这一部分从最小知识开始。先读解释,再把紧跟着的短例子敲一遍。样式体系的核心不是让界面复杂,而是让重复外观集中管理。

1. 为什么需要样式体系

如果每个按钮都这样写:

<Button Background="#2563EB" Foreground="White" Padding="12,6" Content="保存" />

页面能运行,但问题是:

  • 颜色重复。
  • 内边距重复。
  • 多个页面要改同一种按钮时,需要到处找。
  • 有的按钮漏改后,界面不统一。

样式体系就是把这些重复内容集中起来。

2. Resource 是什么

资源是可复用的值。

<SolidColorBrush x:Key="PrimaryBrush" Color="#2563EB" />

这里定义了一个名字叫 PrimaryBrush 的颜色画刷。

使用时:

Foreground="{StaticResource PrimaryBrush}"

意思是从资源里取出 PrimaryBrush

3. Style 是什么

样式是一组外观规则。

<Style Selector="Button.primary"> <Setter Property="Background" Value="{StaticResource PrimaryBrush}" /> <Setter Property="Foreground" Value="White" /> <Setter Property="Padding" Value="12,6" /> </Style>

这条规则表示:带 primary 类的按钮,使用指定背景、文字颜色和内边距。

4. Selector 是什么

Selector 决定样式作用到哪些控件。

Selector含义
Button所有按钮
Button.primaryprimary 类的按钮
Button.dangerdanger 类的按钮
TextBlock.titletitle 类的文字
Border.cardcard 类的边框区域

本页推荐先用 Button.primary 这种写法,不要一开始就写 Button 影响所有按钮。

5. Classes 是什么

Classes 是给控件贴样式标签。

<Button Classes="primary" Content="保存" />

如果全局有:

<Style Selector="Button.primary">

这个按钮就会套用该样式。

没有写 Classes="primary" 的按钮不会套用这条样式。

6. Application.Resources 和 Window.Resources 的区别

位置作用范围适合放什么
Application.Resources整个应用全局颜色、全局尺寸
Window.Resources当前窗口当前页面专用资源
某个容器的 .Resources当前容器内部某一块局部资源

如果只有一个页面用,就先放 Window.Resources。如果多个页面都要用,再放到 App.axaml

7. Application.Styles 和 Window.Styles 的区别

位置作用范围适合场景
Application.Styles全应用主按钮、危险按钮、标题样式
Window.Styles当前窗口当前页面特殊样式
StackPanel.Styles当前容器内部局部实验或小区域样式

全局样式要谨慎。放全局意味着所有页面都可能用到它。

8. 样式和业务逻辑的边界

样式只管外观,不管业务。

适合放样式:

  • 背景色。
  • 字号。
  • 字体粗细。
  • 内边距。
  • 边框。

不适合放样式:

  • 保存逻辑。
  • 删除规则。
  • 价格校验。
  • 列表数据。

业务逻辑仍然放 ViewModel 或 Service。

样式体系常用写法速查

功能练习优先用默认样式;只有出现重复外观时,再提取资源或样式。

需求写法说明
定义资源<SolidColorBrush x:Key="PrimaryBrush" ... />给值起名字
引用资源{StaticResource PrimaryBrush}使用资源
定义样式<Style Selector="Button.primary">命中指定按钮
使用样式类Classes="primary"套用样式
控件类型选择器Style Selector="TextBlock"影响所有 TextBlock
class 选择器Style Selector="Button.primary"只影响指定 class
全局样式App.axaml全应用可用
局部样式当前窗口资源只影响当前页面

判断顺序:

能用默认样式 -> 先不加样式 多个地方重复值 -> 提取资源 多个控件重复外观 -> 提取 Style

第二部分:把知识组合成完整例子

今天要做的是全局样式:把颜色和按钮外观放到 App.axaml,然后在 MainWindow.axaml 里直接使用。

App.axaml

把下面内容放到 App.axaml

<Application xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Class="ProductApp.App" RequestedThemeVariant="Default"> <Application.Resources> <SolidColorBrush x:Key="PrimaryBrush" Color="#2563EB" /> <SolidColorBrush x:Key="DangerBrush" Color="#DC2626" /> <SolidColorBrush x:Key="CardBorderBrush" Color="#DDDDDD" /> </Application.Resources> <Application.Styles> <FluentTheme /> <Style Selector="TextBlock.title"> <Setter Property="FontSize" Value="24" /> <Setter Property="FontWeight" Value="Bold" /> <Setter Property="Foreground" Value="{StaticResource PrimaryBrush}" /> </Style> <Style Selector="Border.card"> <Setter Property="BorderBrush" Value="{StaticResource CardBorderBrush}" /> <Setter Property="BorderThickness" Value="1" /> <Setter Property="Padding" Value="16" /> </Style> <Style Selector="Button.primary"> <Setter Property="Background" Value="{StaticResource PrimaryBrush}" /> <Setter Property="Foreground" Value="White" /> <Setter Property="Padding" Value="12,6" /> </Style> <Style Selector="Button.danger"> <Setter Property="Background" Value="{StaticResource DangerBrush}" /> <Setter Property="Foreground" Value="White" /> <Setter Property="Padding" Value="12,6" /> </Style> </Application.Styles> </Application>

Views/MainWindow.axaml

把下面内容放到 Views/MainWindow.axaml

<Window xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Class="ProductApp.Views.MainWindow" Width="620" Height="360" Title="样式体系"> <StackPanel Margin="20" Spacing="12"> <TextBlock Classes="title" Text="商品管理" /> <Border Classes="card"> <StackPanel Spacing="8"> <TextBlock Text="名称:Keyboard" /> <TextBlock Text="价格:199" /> <StackPanel Orientation="Horizontal" Spacing="8"> <Button Classes="primary" Content="保存" /> <Button Content="取消" /> <Button Classes="danger" Content="删除" /> </StackPanel> </StackPanel> </Border> </StackPanel> </Window>

先用一句话理解

App.axaml 定义全局资源和样式,页面控件通过 Classes="primary"Classes="title"Classes="card" 选择要使用的样式。

第三部分:跟着敲代码

从这里开始动手。今天会改两个文件:App.axamlViews/MainWindow.axaml

例子 1:先定义全局颜色资源

App.axaml 里添加:

<Application.Resources> <SolidColorBrush x:Key="PrimaryBrush" Color="#2563EB" /> <SolidColorBrush x:Key="DangerBrush" Color="#DC2626" /> <SolidColorBrush x:Key="CardBorderBrush" Color="#DDDDDD" /> </Application.Resources>

这一步只定义资源,还没有样式。

例子 2:定义主按钮样式

Application.Styles 里保留模板自带的 <FluentTheme />,再添加:

<Style Selector="Button.primary"> <Setter Property="Background" Value="{StaticResource PrimaryBrush}" /> <Setter Property="Foreground" Value="White" /> <Setter Property="Padding" Value="12,6" /> </Style>

注意:FluentTheme 不要删,它是 Avalonia 默认主题。

例子 3:页面里使用样式类

MainWindow.axaml 里写:

<Button Classes="primary" Content="保存" />

这个按钮会使用全局 Button.primary 样式。

例子 4:完整页面

完整代码使用第一部分的 App.axamlViews/MainWindow.axaml

常见错误和修法

错误为什么错修法
一开始就写大量样式容易掩盖功能问题先让功能可用,再抽样式
选择器写错样式不会生效先从简单控件选择器开始
样式影响范围太大其他页面也被改到用类选择器或局部资源缩小范围
样式里写业务状态逻辑和外观混在一起业务状态放 ViewModel
忘记保留默认可读性外观变了但难用优先保证文字、间距、状态清楚

小白重复敲写训练

样式体系要通过“同一个样式控制多个控件”来记。

训练 1:按控件类型设置样式

<Window.Styles> <Style Selector="Button"> <Setter Property="Padding" Value="14,8" /> <Setter Property="Margin" Value="4" /> </Style> </Window.Styles>

放三个按钮,确认都受到影响。

训练 2:使用样式类

<Style Selector="Button.danger"> <Setter Property="Background" Value="#DC2626" /> <Setter Property="Foreground" Value="White" /> </Style> <Button Classes="danger" Content="删除" />

改动任务:再定义 primary 类。

训练 3:组合选择器状态

<Style Selector="Button.danger:pointerover"> <Setter Property="Background" Value="#B91C1C" /> </Style>

第三遍分别测试普通、悬停和禁用状态。

每日小测

做完本页后,用这 5 题检查是否真的掌握。

1. 判断题

本页的目标不是只把代码运行起来,还要能说清楚“为什么这样写”。

答案:对。能运行只是第一步,能解释原理、常用操作和常见错误,才说明本页内容进入了可复用能力。

2. 填空题

本页主题是:样式体系。今天至少要掌握的 3 个点是:

1. 知道 `Resources` 是可复用的值。 2. 知道 `Styles` 是可复用的外观规则。 3. 会在 `App.axaml` 里定义全局颜色资源。

答案:以上 3 点必须能用自己的代码跑通,不能只停留在阅读。

3. 流程题

遇到本页相关功能时,先按什么顺序处理?

答案:先看完整例子,确认最终效果;再读原理和名词;然后跟着第三部分从空项目敲代码;最后对照作业答案检查。

4. 找错误题

如果本页代码运行失败,第一步应该做什么?

答案:先看终端或 IDE 里的第一条错误,找到文件名和行号;不要同时改很多地方。再回到本页的“常见错误和修法”表格,对照错误类型逐项排查。

5. 改需求题

在本页完整例子跑通后,至少改一个小需求。

可选改法:

  • 改一个字段名称。
  • 多加一个校验条件。
  • 多输出一行结果。
  • 把固定数据改成用户输入。
  • 把一次处理改成多条数据处理。

答案标准:修改后能重新运行,并能说明这次修改影响了哪一段逻辑。重点检查:知道 Resources 是可复用的值。。

上位机专项练习

状态样式必须一眼可辨,但不能只依赖颜色。文字、图标和颜色要一起表达在线、离线与报警。

下面 3 个例子都要亲手敲。先运行原代码,再完成每个例子后面的改动任务。

专项例子 1:在线状态样式

<Style Selector="Border.online"> <Setter Property="Background" Value="#E8F5E9" /> <Setter Property="BorderBrush" Value="#2E7D32" /> </Style> <Border Classes="online" Padding="10"><TextBlock Text="在线" /></Border>

运行结果或界面效果:

绿色底色加“在线”文字

改动任务: 增加离线灰色样式。

专项例子 2:报警状态不只靠红色

<StackPanel Orientation="Horizontal" Spacing="8"> <TextBlock Text="!" FontWeight="Bold" /> <TextBlock Text="高温报警:85.2 C" /> </StackPanel>

运行结果或界面效果:

符号和文字共同提示报警

改动任务: 增加报警时间。

专项例子 3:用伪类切换样式

<Style Selector="Button:disabled"> <Setter Property="Opacity" Value="0.45" /> </Style> <Button Content="开始采集" IsEnabled="{Binding CanStart}" />

运行结果或界面效果:

不可用按钮视觉上变淡

改动任务: 为 pointerover 增加背景变化。

第四部分:作业完整答案

这一部分给出当天作业的完整答案。先照第三部分敲一遍,再用这里检查结果。

作业要求

做一个全局样式练习:

  1. App.axaml 定义 PrimaryBrush
  2. App.axaml 定义 DangerBrush
  3. App.axaml 定义 Button.primary
  4. App.axaml 定义 Button.danger
  5. MainWindow.axaml 使用 Classes="primary"
  6. MainWindow.axaml 使用 Classes="danger"
  7. 普通取消按钮不加样式类,保持默认外观。

App.axaml 完整答案

<Application xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Class="ProductApp.App" RequestedThemeVariant="Default"> <Application.Resources> <SolidColorBrush x:Key="PrimaryBrush" Color="#2563EB" /> <SolidColorBrush x:Key="DangerBrush" Color="#DC2626" /> <SolidColorBrush x:Key="CardBorderBrush" Color="#DDDDDD" /> </Application.Resources> <Application.Styles> <FluentTheme /> <Style Selector="TextBlock.title"> <Setter Property="FontSize" Value="24" /> <Setter Property="FontWeight" Value="Bold" /> <Setter Property="Foreground" Value="{StaticResource PrimaryBrush}" /> </Style> <Style Selector="Border.card"> <Setter Property="BorderBrush" Value="{StaticResource CardBorderBrush}" /> <Setter Property="BorderThickness" Value="1" /> <Setter Property="Padding" Value="16" /> </Style> <Style Selector="Button.primary"> <Setter Property="Background" Value="{StaticResource PrimaryBrush}" /> <Setter Property="Foreground" Value="White" /> <Setter Property="Padding" Value="12,6" /> </Style> <Style Selector="Button.danger"> <Setter Property="Background" Value="{StaticResource DangerBrush}" /> <Setter Property="Foreground" Value="White" /> <Setter Property="Padding" Value="12,6" /> </Style> </Application.Styles> </Application>

Views/MainWindow.axaml 完整答案

<Window xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Class="ProductApp.Views.MainWindow" Width="620" Height="360" Title="样式体系"> <StackPanel Margin="20" Spacing="12"> <TextBlock Classes="title" Text="商品管理" /> <Border Classes="card"> <StackPanel Spacing="8"> <TextBlock Text="名称:Keyboard" /> <TextBlock Text="价格:199" /> <StackPanel Orientation="Horizontal" Spacing="8"> <Button Classes="primary" Content="保存" /> <Button Content="取消" /> <Button Classes="danger" Content="删除" /> </StackPanel> </StackPanel> </Border> </StackPanel> </Window>

必须验证的结果

控件应该看到
标题使用 TextBlock.title 的字号和主色
保存按钮使用主按钮样式
删除按钮使用危险按钮样式
取消按钮保持默认按钮样式
卡片区域有边框和内边距

如果样式不生效,按这个顺序检查

  1. 检查 App.axaml 里是否保留 <FluentTheme />
  2. 检查资源名是否一致,比如 PrimaryBrush 不能写成 PrimaryColor
  3. 检查样式选择器是否是 Button.primary
  4. 检查按钮是否写了 Classes="primary"
  5. 检查样式是否放在 Application.Styles 内。

今天真正要掌握的闭环

Application.Resources 定义可复用值 -> Application.Styles 定义全局外观规则 -> Selector 决定样式命中哪些控件 -> Classes 给控件选择样式 -> 页面不再重复写同样颜色和内边距

样式体系的目标是减少重复,不是让页面变复杂。