| 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 |
Freezable Performance
Rules for using Freeze() on WPF Freezable objects to maximize rendering performance.
Rule: Freeze All Freezable Objects
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.
Why Freeze Matters
| 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.
Correct vs Incorrect
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));
}
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));
}
OnRender Pattern: Create in Constructor, Reuse in OnRender
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)
{
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.