From wpf-dev-pack
Optimizes WPF memory usage via Freezable patterns, fixes common leaks from events, CompositionTarget.Rendering, timers, bindings, and images, with diagnostic checklists. Use for memory growth or leak debugging.
How this skill is triggered — by the user, by Claude, or both
Slash command
/wpf-dev-pack:optimizing-wpf-memoryopusThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
| Benefit | Description |
| Benefit | Description |
|---|---|
| Thread-safe | Can be used across threads |
| No change tracking | Reduces overhead |
| Renderer optimization | Better GPU utilization |
// Always freeze static resources
var brush = new SolidColorBrush(Colors.Red);
brush.Freeze();
var pen = new Pen(Brushes.Black, 1);
pen.Freeze();
<Window xmlns:po="http://schemas.microsoft.com/winfx/2006/xaml/presentation/options"
mc:Ignorable="po">
<Window.Resources>
<SolidColorBrush x:Key="FrozenBrush" Color="Red" po:Freeze="True"/>
</Window.Resources>
</Window>
if (brush.CanFreeze)
brush.Freeze();
else
// Has bindings or animations - cannot freeze
var clone = frozenBrush.Clone(); // Creates unfrozen copy
clone.Color = Colors.Blue;
clone.Freeze(); // Freeze again if needed
// ❌ LEAK: Static event holds reference
SomeStaticClass.StaticEvent += OnEvent;
// ✅ FIX: Unsubscribe in Unloaded
Unloaded += (s, e) => SomeStaticClass.StaticEvent -= OnEvent;
// ❌ LEAK: Never unsubscribed
CompositionTarget.Rendering += OnRendering;
// ✅ FIX: Always unsubscribe
Loaded += (s, e) => CompositionTarget.Rendering += OnRendering;
Unloaded += (s, e) => CompositionTarget.Rendering -= OnRendering;
// ❌ LEAK: PropertyDescriptor retained
public string Name { get; set; } // No INPC
// ✅ FIX: Implement INPC
public string Name
{
get => _name;
set { _name = value; OnPropertyChanged(); }
}
// ❌ LEAK: Timer keeps running
_timer = new DispatcherTimer();
_timer.Tick += OnTick;
_timer.Start();
// ✅ FIX: Stop and cleanup
Unloaded += (s, e) =>
{
_timer.Stop();
_timer.Tick -= OnTick;
};
// ❌ LEAK: Stream kept open
var bitmap = new BitmapImage(new Uri(path));
// ✅ FIX: Load immediately and release stream
var bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.CacheOption = BitmapCacheOption.OnLoad;
bitmap.UriSource = new Uri(path);
bitmap.EndInit();
bitmap.Freeze();
BitmapCacheOption.OnLoad| Tool | Purpose |
|---|---|
| VS Diagnostic Tools | Real-time memory snapshots |
| dotMemory | Detailed retention paths |
| PerfView | GC and allocation analysis |
public static class MemoryMonitor
{
public static void LogMemory(string context)
{
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
var mem = GC.GetTotalMemory(true) / 1024.0 / 1024.0;
Debug.WriteLine($"[{context}] Memory: {mem:F2} MB");
}
}
public static class FrozenResources
{
public static SolidColorBrush CreateBrush(Color color)
{
var brush = new SolidColorBrush(color);
brush.Freeze();
return brush;
}
public static Pen CreatePen(Color color, double thickness)
{
var pen = new Pen(CreateBrush(color), thickness);
pen.Freeze();
return pen;
}
}
npx claudepluginhub christian289/dotnet-with-claudecode --plugin wpf-dev-packExplains WPF rendering pipeline including Measure/Arrange/Render passes, invalidation methods, and hardware acceleration tiers. Use for debugging layouts, optimizing performance, or diagnosing software rendering.
Building WPF on .NET 8+. Host builder, MVVM Toolkit, Fluent theme, performance, modern C# patterns.
Guides .NET MAUI performance optimization including profiling with dotnet-trace, compiled bindings, layout efficiency, image optimization, trimming, NativeAOT, and startup improvements. For slow apps, large sizes, or poor responsiveness.