一键导入
wpf-rule-freezable-performance
WPF Freezable performance rules: Freeze() all Brush/Pen/Geometry; create-and-freeze in constructor, reuse in OnRender.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
WPF Freezable performance rules: Freeze() all Brush/Pen/Geometry; create-and-freeze in constructor, reuse in OnRender.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
WPF IValueConverter rules: MarkupExtension singleton, pure functions, null/UnsetValue handling, TemplateBinding.
WPF MVVM layer-separation rules: no System.Windows in ViewModels, BCL-only types, CommunityToolkit.Mvvm base classes. Preloaded into MVVM-related wpf-dev-pack agents.
Banned wpf-dev-pack patterns (P-001..P-004): ViewModelLocator, code-behind DataContext, Stateless ViewModel, mixing composition paths.
WPF rendering anti-patterns: no InvalidateVisual in loops, no resource allocation in OnRender.
WPF ResourceDictionary rules: Generic.xaml as MergedDictionaries hub only, per-control style files, resource order.
View-ViewModel wiring for CommunityToolkit.Mvvm: Mappings.xaml + implicit DataTemplate (ViewModel First).
| name | wpf-rule-freezable-performance |
| description | WPF Freezable performance rules: Freeze() all Brush/Pen/Geometry; create-and-freeze in constructor, reuse in OnRender. |
| user-invocable | false |
Rules for using Freeze() on WPF Freezable objects to maximize rendering performance.
Call Freeze() on every Freezable after it is fully configured and before it is used for rendering.
Applies to: Brush, Pen, Geometry, Transform, PathGeometry, GradientBrush, ImageBrush, DrawingGroup, and all other Freezable subclasses.
| Without Freeze | With Freeze |
|---|---|
| Object tracked for change notifications | No change tracking overhead |
| Cannot be shared across threads | Sharable across all threads |
| WPF retains full change-event infrastructure | Infrastructure freed immediately |
| Higher memory footprint | Minimal memory footprint |
Frozen objects are immutable. WPF can cache and reuse them across render passes without defensive copies.
// Incorrect: brush created but never frozen
protected override void OnRender(DrawingContext dc)
{
var brush = new SolidColorBrush(Colors.CornflowerBlue);
var pen = new Pen(brush, 2.0);
dc.DrawRectangle(brush, pen, new Rect(0, 0, 100, 50));
}
// Correct: freeze immediately after configuration
protected override void OnRender(DrawingContext dc)
{
var brush = new SolidColorBrush(Colors.CornflowerBlue);
brush.Freeze();
var pen = new Pen(brush, 2.0);
pen.Freeze();
dc.DrawRectangle(brush, pen, new Rect(0, 0, 100, 50));
}
Creating Freezable objects inside OnRender allocates on every paint cycle.
Create them once in the constructor (or a lazy initializer), freeze them, then reuse the frozen instances in every OnRender call.
public class MyVisual : FrameworkElement
{
private readonly SolidColorBrush _fillBrush;
private readonly Pen _borderPen;
public MyVisual()
{
_fillBrush = new SolidColorBrush(Colors.CornflowerBlue);
_fillBrush.Freeze();
_borderPen = new Pen(Brushes.DarkBlue, 1.5);
_borderPen.Freeze();
}
protected override void OnRender(DrawingContext dc)
{
// No allocation here — reuse frozen instances
dc.DrawRectangle(_fillBrush, _borderPen, new Rect(0, 0, ActualWidth, ActualHeight));
}
}
If a property changes and a new brush is needed, create and freeze the replacement, then call InvalidateVisual() once.