Loading...
Loading...
Provides high-performance WPF rendering techniques including DrawingVisual, WriteableBitmap, CompositionTarget.Rendering, and BitmapCache. Use when implementing real-time graphics, game loops, particle systems, charts, or when Shape controls cause performance issues.
npx skill4agent add christian289/dotnet-with-claudecode rendering-wpf-high-performance| Technique | Use Case | Performance |
|---|---|---|
| DrawingVisual | 1K-100K shapes | 10-50x faster than Shape |
| WriteableBitmap | Pixel manipulation, heatmaps | Fastest for raw pixels |
| CompositionTarget.Rendering | Game loops, real-time animation | ~60 FPS frame callback |
| BitmapCache | Complex static visuals | GPU texture caching |
public class ChartVisual : FrameworkElement
{
private readonly VisualCollection _visuals;
public ChartVisual() => _visuals = new VisualCollection(this);
public void Render(IEnumerable<Point> points)
{
_visuals.Clear();
var visual = new DrawingVisual();
using (var dc = visual.RenderOpen())
{
var pen = new Pen(Brushes.Blue, 1);
pen.Freeze();
var prev = points.First();
foreach (var pt in points.Skip(1))
{
dc.DrawLine(pen, prev, pt);
prev = pt;
}
}
_visuals.Add(visual);
}
protected override int VisualChildrenCount => _visuals.Count;
protected override Visual GetVisualChild(int index) => _visuals[index];
}Freeze()StreamGeometryPathGeometryVisualChildrenCountGetVisualChildpublic class PixelCanvas : Image
{
private WriteableBitmap _bitmap;
public void Initialize(int width, int height)
{
_bitmap = new WriteableBitmap(width, height, 96, 96, PixelFormats.Bgra32, null);
Source = _bitmap;
}
public unsafe void DrawPixel(int x, int y, Color color)
{
_bitmap.Lock();
try
{
var ptr = (byte*)_bitmap.BackBuffer;
int stride = _bitmap.BackBufferStride;
int offset = y * stride + x * 4;
ptr[offset + 0] = color.B;
ptr[offset + 1] = color.G;
ptr[offset + 2] = color.R;
ptr[offset + 3] = color.A;
_bitmap.AddDirtyRect(new Int32Rect(x, y, 1, 1));
}
finally { _bitmap.Unlock(); }
}
}<AllowUnsafeBlocks>true</AllowUnsafeBlocks>AddDirtyRectpublic class GameLoop
{
private TimeSpan _lastRender;
public void Start()
{
CompositionTarget.Rendering += OnRendering;
}
public void Stop()
{
CompositionTarget.Rendering -= OnRendering;
}
private void OnRendering(object sender, EventArgs e)
{
var args = (RenderingEventArgs)e;
// Skip duplicate frames
if (args.RenderingTime == _lastRender) return;
var deltaTime = (args.RenderingTime - _lastRender).TotalSeconds;
_lastRender = args.RenderingTime;
Update(deltaTime);
Render();
}
private void Update(double dt) { /* Physics, AI */ }
private void Render() { /* Drawing */ }
}Unloaded<Border>
<Border.CacheMode>
<BitmapCache RenderAtScale="1" EnableClearType="False"/>
</Border.CacheMode>
<!-- Complex content here -->
</Border>element.CacheMode = new BitmapCache { RenderAtScale = 1.0 };| Method | 10K Points | Use Case |
|---|---|---|
| Shape (Ellipse) | ~500ms | <100 elements |
| DrawingVisual | ~20ms | 1K-100K shapes |
| WriteableBitmap (managed) | ~5ms | Pixel grids |
| WriteableBitmap (unsafe) | ~1ms | Real-time heatmaps |