rendering-wpf-high-performance

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

High-Performance WPF Rendering

高性能WPF渲染

Quick Reference

快速参考

TechniqueUse CasePerformance
DrawingVisual1K-100K shapes10-50x faster than Shape
WriteableBitmapPixel manipulation, heatmapsFastest for raw pixels
CompositionTarget.RenderingGame loops, real-time animation~60 FPS frame callback
BitmapCacheComplex static visualsGPU texture caching
技术适用场景性能
DrawingVisual1K-100K个形状比Shape快10-50倍
WriteableBitmap像素操作、热力图原始像素处理最快
CompositionTarget.Rendering游戏循环、实时动画~60 FPS帧回调
BitmapCache复杂静态视觉对象GPU纹理缓存

1. DrawingVisual Pattern

1. DrawingVisual模式

Lightweight visual for high-volume rendering without layout overhead.
csharp
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];
}
Key Points:
  • Always
    Freeze()
    Brush/Pen for thread safety and performance
  • Use
    StreamGeometry
    instead of
    PathGeometry
    for read-only paths
  • Override
    VisualChildrenCount
    and
    GetVisualChild
用于高容量渲染的轻量级视觉对象,无布局开销。
csharp
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];
}
关键点:
  • 始终对Brush/Pen执行
    Freeze()
    操作以保障线程安全和性能
  • 针对只读路径使用
    StreamGeometry
    而非
    PathGeometry
  • 重写
    VisualChildrenCount
    GetVisualChild
    方法

2. WriteableBitmap Pattern

2. WriteableBitmap模式

Direct pixel manipulation for maximum performance.
csharp
public 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(); }
    }
}
Key Points:
  • Enable
    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
    in .csproj
  • Use
    AddDirtyRect
    for partial updates
  • BGRA32 format: Blue, Green, Red, Alpha order
直接操作像素以实现最高性能。
csharp
public 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(); }
    }
}
关键点:
  • 在.csproj文件中启用
    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
  • 使用
    AddDirtyRect
    实现局部更新
  • BGRA32格式:按蓝、绿、红、Alpha顺序排列

3. CompositionTarget.Rendering

3. CompositionTarget.Rendering

Per-frame callback for game loops and real-time updates.
csharp
public 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 */ }
}
Critical: Always unsubscribe in
Unloaded
event to prevent memory leaks.
用于游戏循环和实时更新的逐帧回调。
csharp
public 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;

        // 跳过重复帧
        if (args.RenderingTime == _lastRender) return;

        var deltaTime = (args.RenderingTime - _lastRender).TotalSeconds;
        _lastRender = args.RenderingTime;

        Update(deltaTime);
        Render();
    }

    private void Update(double dt) { /* 物理逻辑、AI逻辑 */ }
    private void Render() { /* 绘制逻辑 */ }
}
重要提示: 始终在
Unloaded
事件中取消订阅以避免内存泄漏。

4. BitmapCache

4. BitmapCache

GPU-cached rendering for complex but static visuals.
xml
<Border>
    <Border.CacheMode>
        <BitmapCache RenderAtScale="1" EnableClearType="False"/>
    </Border.CacheMode>
    <!-- Complex content here -->
</Border>
csharp
element.CacheMode = new BitmapCache { RenderAtScale = 1.0 };
When to Use:
  • ✅ Transform animations (rotate, scale, translate)
  • ✅ Complex PathGeometry, DrawingVisual
  • ❌ Frequently changing content
  • ❌ Simple shapes (Rectangle, Ellipse)
针对复杂但静态的视觉对象的GPU缓存渲染。
xml
<Border>
    <Border.CacheMode>
        <BitmapCache RenderAtScale="1" EnableClearType="False"/>
    </Border.CacheMode>
    <!-- 复杂内容放在此处 -->
</Border>
csharp
element.CacheMode = new BitmapCache { RenderAtScale = 1.0 };
适用场景:
  • ✅ 变换动画(旋转、缩放、平移)
  • ✅ 复杂PathGeometry、DrawingVisual
  • ❌ 频繁变化的内容
  • ❌ 简单形状(Rectangle、Ellipse)

Performance Comparison

性能对比

Method10K PointsUse Case
Shape (Ellipse)~500ms<100 elements
DrawingVisual~20ms1K-100K shapes
WriteableBitmap (managed)~5msPixel grids
WriteableBitmap (unsafe)~1msReal-time heatmaps
方法1万点耗时适用场景
Shape (Ellipse)~500ms元素数量<100的场景
DrawingVisual~20ms1K-100K个形状的场景
WriteableBitmap (托管实现)~5ms像素网格场景
WriteableBitmap (不安全实现)~1ms实时热力图场景

Related References

相关参考

For detailed implementation patterns, see:
  • reference/drawingvisual-advanced.md - Hit testing, transforms
  • reference/writeablebitmap-algorithms.md - Bresenham, flood fill
  • reference/compositiontarget-examples.md - Particle systems
  • reference/bitmapcache-optimization.md - Memory management
如需了解详细实现模式,请参阅:
  • reference/drawingvisual-advanced.md - 命中测试、变换
  • reference/writeablebitmap-algorithms.md - 布雷森汉姆直线算法、泛洪填充
  • reference/compositiontarget-examples.md - 粒子系统
  • reference/bitmapcache-optimization.md - 内存管理