文章目录
- 1.StaticResource (一次性快照)
-
- [StaticResources 适用场合](#StaticResources 适用场合)
- 2.DynamicResource (实时连接)
-
- [Dynamic Resource 使用场合](#Dynamic Resource 使用场合)
- 3.性能与限制
-
- [为什么要优先使用 StaticResource?](#为什么要优先使用 StaticResource?)
- [什么时候必须使用 DynamicResource?](#什么时候必须使用 DynamicResource?)
- 4.什么是WPF资源(Resource)?
在 WPF 或 Avalonia 开发中,
StaticResource(静态资源)与DynamicResource(动态资源)的本质区别在于 资源查找的时机 以及 对变化监控的开销。
| 特性 | StaticResource (静态资源) | DynamicResource (动态资源) |
|---|---|---|
| 解析时机 | 加载时 (Load-time)。XAML 加载并实例化对象时查找一次。 | 运行时 (Run-time)。在对象生命周期内,随用随找。 |
| 性能开销 | 低。一次性查找并赋值,没有后续开销。 | 高。系统需维护一个表达式连接,以便随时监听资源变化。 |
| 资源变化响应 | 不响应。如果 ResourceDictionary 里的对象变了,UI 不会更新。 | 响应。资源一旦被重新赋值,UI 立即自动更新。 |
| 前向引用 | 不支持。资源必须定义在使用点之前。 | 支持。资源可以定义在 XAML 文件的任何位置,甚至运行时动态加载。 |
| 应用场景 | 布局基础色、固定的图标、转换器 (Converters)。 | 主题切换 (Theme)、系统颜色、多语言热切换。 |
静态资源(StaticResource) & 动态资源(DynamicResource)
1.StaticResource (一次性快照)
当 XAML 解析器遇到 StaticResource 时,它会立即按照"资源查找顺序"去查找该 Key 对应的值。一旦找到,就将该值赋给控件属性。
类比: 就像你在餐馆点餐时,服务员直接把做好的菜端给你。之后后厨就算把这道菜的做法改了,你手里的那盘菜也不会变。
StaticResource 查找逻辑
- 元素自身资源。
- 逻辑树向上冒泡 :检查父容器,直到
Window。 - Application 资源 (
App.xaml)。 - 失败处理:抛出异常。
StaticResources 适用场合
- 在资源第一次引用之后无需再修改资源的值。
- 资源引用不会基于运行时的行为进行重新计算,比如在重新加载Page/Window的时候。
- 当需要设置的属性不是DependencyObject或Freezable类型的时候,用StaticResource。
- 当需要将资源编译到dll中,并打包为程序的一部份,或者希望在各应用程序之间共享时,也使用StaticResource。
- 当需要为一个自定义控件创建一个Theme,并Theme中使用资源,就需要使用StaticResource。因为StaticResource的资源查找行为时可预测的,并且本身包含在Theme中。而对于DynamicResource,即使资源是定义在Theme中,也只能等到运行时确定,导致一些可能意料不到的情况发生。
- 当需要使用资源设置大量的依赖属性(Dependency Property)的时候。
由于依赖属性具有属性系统提供的值缓存机制,所以,如果能在程序装载时设置依赖属性的值,这样,依赖属性就不需要检查自己的值并返回最后的有效值了。
2.DynamicResource (实时连接)
当使用 DynamicResource 时,系统并不直接赋值,而是创建一个 DeferredResourceReference。它在后台保持一个"挂钩",每当该 Key 在资源字典中被重新定义时,系统会通知所有引用该 Key 的控件进行重绘。
类比: 就像你订阅了一个电视频道。频道播什么,你电视里就显示什么。后台换了节目,你的画面也会跟着变。
DynamicResource 查找逻辑
- 元素自身资源(包括 Style 或 Template 内部的资源)。
- 逻辑树向上冒泡。
- Application 资源。
- Theme 字典:当前 Windows 主题(如 Aero.NormalColor.xaml)中的资源。
- 系统资源 :
SystemColors,SystemFonts,SystemParameters。 - 失败处理 :返回
DependencyProperty.UnsetValue(通常 UI 留白或显示默认色),不报错。
Dynamic Resource 使用场合
- 资源的值依赖一些条件,而该条件直到运行时才能确定。
- 包括系统资源,或是用户可设置的资源。比如:可以创建引用系统属性诸如SystemColors,SystemFonts来设置值,而这些属性是动态的,它们的值又来自于运行环境和操作系统。
- 为自定义控件引用或创建Theme Style。
- 希望在程序运行期间调整资源字典的内容时。
- 希望资源可以向前引用时(如上面在Canvas中引用innerLgbResource一样)
- 资源文件很大,希望在运行时才加载。
- 要创建的Style的值可能来自于其它值,而这些值又依赖于Theme或用户的设置。
- 当引用资源的元素的父元素有可能在运行期改变,这个时候也需要使用动态资源。因为父元素的改变将导致资源查询的范围。
- Dynamic resource的限制条件:属性必须是依赖属性,或是Freezable的。
资源可以作为静态资源 或动态资源进行引用。这是通过使用 StaticResource 标记扩展或 DynamicResource 标记扩展完成的。
- StaticResource 通过替换已定义资源的值来为 XAML 属性提供值。
- DynamicResource通过将值推迟为对资源的运行时引用来为XAML 属性提供值。动态资源引用强制在每次访问此类资源时都重新进行查找。
通常来说,不需要在运行时更改的资源使用静态资源;而需要在运行时更改的资源使用动态资源。动态资源需要使用的系统开销大于静态资源的系统开销。
xml
<Window.Resources>
<SolidColorBrush x:Key="MyBrush" Color="Blue" />
</Window.Resources>
<StackPanel>
<Button Background="{StaticResource MyBrush}" Content="静态" />
<Button Background="{DynamicResource MyBrush}" Content="动态" />
</StackPanel>
3.性能与限制
为什么要优先使用 StaticResource?
作为软件工程师,性能优化是核心考量。StaticResource 的查找效率极高,因为它不需要在内存中维护复杂的依赖追踪关系。如果 UI 中的上千个控件都用 DynamicResource 引用颜色,会增加 CPU 的计算负担。
什么时候必须使用 DynamicResource?
1.资源在编译时不可用 :例如引用系统属性 SystemColors.WindowBrush(用户可能在控制面板改颜色)。
2.皮肤/主题热切换:
xml
<Button Background="{DynamicResource ThemeBrush}" />
3.循环引用 :如果你在 ResourceDictionary 内部,某个资源引用了后面才定义的资源,只能用 DynamicResource。
4.什么是WPF资源(Resource)?
资源是存储在 XAML 或可执行文件中的非执行数据。它可以是任何具有默认构造函数的 CLR 对象(如颜色、画刷、控件模板、字符串、甚至是一个复杂的业务对象)。
- 本质:将 UI 的"资产"(Assets)与"逻辑"(Code)分离。
- 核心标志 :
x:Key。每个资源在字典中必须有唯一的键,类似于Dictionary<string, object>。
资源是保存在可执行文件中的一种不可执行数据。在WPF的资源中,几乎可以包含图像、字符串等所有的任意CLR对象,只要对象有一个默认的构造函数和独立的属性。
也就是说,应用程序中非程序代码的内容,比如点阵图、颜色、字型、动画/影片档以及字符串常量值,可将它们从程序中独立出来,单独包装成"资源(Resource)"。
| 特性 | StaticResource | DynamicResource |
|---|---|---|
| 解析时机 | 加载时(Load-time) | 运行时(Run-time) |
| 性能 | 高(直接赋值引用) | 低(需维护监控表达式) |
| 查找顺序 | 逻辑树向上 -> App -> 系统 | 逻辑树向上 -> App -> 当前 Theme -> 系统 |
| 向前引用 | 不支持(必须先定义后引用) | 支持(可以先引用,后定义) |
| 限制条件 | 无 | 属性必须是 依赖属性 或 Freezable |
静态资源(Static Resource),动态资源(Dynamic Resources)。这两者的区别是:静态资源在第一次编译后即确定其对象或值,之后不能对其进行修改。
动态资源则是在运行时决定,当运行过程中真正需要时,才到资源目标中查找其值。因此,我们可以动态地修改它。由于动态资源的运行时才能确定其值,因此效率比静态资源要低。
资源的范围(层级)
WPF提供一个封装和存取资源(resource)的机制,我们可将资源建立在应用程序的不同范围上。WPF中,资源定义的位置决定了该资源的可用范围。资源可以定义在如下范围中:
资源层级的"优先级"逻辑 (Priority)
WPF 遵循**"就近原则"**。这意味着如果同名的 x:Key 同时出现在物件级和应用程序级,物件级会屏蔽(Shadow)掉上层的定义。
| 层级 | 查找代价 | 典型应用场景 |
|---|---|---|
| 物件级 (Object) | 极低 | 仅在此按钮内使用的渐变画刷、特定动画。 |
| 文件级 (Window/Page) | 中 | 页面特有的 ValueConverter、局部业务样式的 DataTrigger。 |
| 应用程序级 (App) | 高 (仅在初始化时) | 全局品牌色、通用控件模板(Button/TextBox 样式)。 |
| 字典级 (Dictionary) | 视合并方式而定 | 跨项目的 StandardStyles.xaml、深/浅色主题包。 |
- 内存陷阱 :定义在
App.xaml中的资源在程序生命周期内永远不会被回收。如果你在应用级定义了非常巨大的位图(Bitmap),请务必小心。 - 逻辑树与视觉树 :资源查找是沿着逻辑树 (Logical Tree) 向上冒泡的。在一些复杂的自定义控件(如使用了
Popup的控件)中,有时会因为逻辑树断开导致找不到资源,这时通常需要用DynamicResource或手动设置Resources代理。
每一个框架级元素(FrameworkElement 或者FrameworkContentElement)都有一个资源属性。每一个在资源字典中的资源都有一个唯一不重复的键值(key),在标签中使用x:Key属性来标识它。一般地,键值是一个字符串,但你也可以用合适的扩展标签来设置为其他对象类型。非字符键值资源使用于特定的WPF区域,尤其是风格、组件资源,以及样式数据等。
什么时候坚持用 StaticResource?
- 性能敏感区 :如
DataTemplate内部(列表滚动时,每行都有大量资源解析)。 - 逻辑固定:转换器(Converters)、固定的间距(Thickness)、基础字体。
- 控件模板内:定义自定义控件的内置皮肤时。
什么时候必须用 DynamicResource?
- 系统环境依赖:引用用户在 Windows 设置中定义的颜色。
- 皮肤热切换:需要在不重启程序的情况下改变 UI 主题。
- 代码动态干预:如果你需要通过 C# 频繁更换某个 Key 指向的对象实例。
资源的查询方式

当资源被存储进资源词典后,我们可以通过两种方式来使用这些资源一一静态方式和动态方式。 Static指的是程序的非执行状态而 Dynamic指的是程序运行状态。对于资源的使用, Static 和 Dynamic也是这个意思。
静态资源( StaticResource) 指的是在程序载入内存时对资源的一次性使用,之后就不再去访问这个资源了
动态资源( DynamicResource) 指的是在程序运行过程中仍然会去访问资源 。动态资源强制在每次访问此类资源时都重新进行查找 。所以动态资源需要使用的系统开销大于静态资源的系统开销。
StaticResource 查询行为不支持向后引用,即不能引用在引用点之后才定义的资源。而DynamicResource可以向后引用,即DynamicResource运行时才查找并加载所定义的资源。