freezable 是 wpf 中可冻结以提升性能和线程安全的对象,需先检查 canfreeze 再调用 freeze();冻结后不可修改,须用 clone() 创建可修改副本;xaml 中可用 o:freeze="true" 自动冻结。

Freezable 是 WPF 中一类“能冻住”的对象,不是所有都能冻,冻了就不能改,但能省资源、跨线程、提性能——关键在于:先问 CanFreeze,再调 Freeze(),别硬来。
怎么判断一个 Freezable 能不能冻结?看 CanFreeze 和 IsFrozen
Freezable 对象(比如 SolidColorBrush、Transform、Geometry)不是生来就能冻的。常见冻结失败原因:
-
CanFreeze返回false:对象正被动画控制、绑定了数据、用了动态资源({DynamicResource ...})、或内部含无法冻结的子对象 -
IsFrozen已为true:已经冻过了,再调Freeze()不报错但也没用 - 没检查就直接
Freeze()→ 抛InvalidOperationException
正确姿势:
SolidColorBrush brush = new SolidColorBrush(Colors.Blue);
if (brush.CanFreeze)
{
brush.Freeze(); // 成功冻结
}
// 后续可安全检查
if (brush.IsFrozen) { /* 安心用 */ }冻结后想改怎么办?必须用 Clone(),不能解冻
Freezable 冻结后是单向操作,没有 Unfreeze()。试图改属性(如 brush.Color = Colors.Red)会立刻抛异常。
要修改,只能克隆一份新的:
-
Clone():返回可修改的副本(深拷贝,不含原绑定/动画) -
CloneCurrentValue():克隆当前值(保留动画效果,但不保留绑定)
示例:
if (brush.IsFrozen)
{
var clone = brush.Clone(); // 新对象,可改
clone.Color = Colors.Green;
myButton.Background = clone;
}XAML 里怎么自动冻结?用 o:Freeze="True"
在资源字典中定义画刷等对象时,加个命名空间和属性就能让 XAML 加载时自动冻结:
<Window xmlns:o="http://schemas.microsoft.com/winfx/2006/xaml/presentation/options">
<Window.Resources>
<SolidColorBrush x:Key="BgBrush" Color="Orange" o:Freeze="True"/>
</Window.Resources>
</Window>注意:o:Freeze 不是附加属性,是 XAML 处理器内置支持的编译期指令;它只对可冻结的类型生效,且同样受 CanFreeze 约束——如果资源里绑了 {Binding},这行就静默失效。
为什么值得花这一步?性能和线程安全真有差别
冻结不只是“防止误改”,它直接影响运行时行为:
- 图形系统不再监听变更通知,减少 CPU 和内存开销(尤其大量复用画刷时)
- 冻结对象是线程安全的,可在后台线程创建并传给 UI 线程使用(未冻结的
Brush只能在创建它的线程访问) - WPF 渲染管线对冻结对象做额外优化,比如跳过某些校验逻辑
典型场景:自定义控件模板中大量使用静态画刷、图标 Geometry、预设 Transform —— 这些几乎从不修改,不冻白不冻。
最常被忽略的一点:动画中的对象一旦参与动画,CanFreeze 就变成 false,哪怕动画已停。所以别在动画结束后幻想“现在可以冻了”——得先停止动画、清除动画时钟、解除绑定,才可能重新满足冻结条件。










