rendering-wpf-high-performance
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseHigh-Performance WPF Rendering
高性能WPF渲染
Quick Reference
快速参考
| 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 |
| 技术 | 适用场景 | 性能 |
|---|---|---|
| DrawingVisual | 1K-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 Brush/Pen for thread safety and performance
Freeze() - Use instead of
StreamGeometryfor read-only pathsPathGeometry - Override and
VisualChildrenCountGetVisualChild
用于高容量渲染的轻量级视觉对象,无布局开销。
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() - 针对只读路径使用而非
StreamGeometryPathGeometry - 重写和
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 in .csproj
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> - Use for partial updates
AddDirtyRect - 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 event to prevent memory leaks.
Unloaded用于游戏循环和实时更新的逐帧回调。
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() { /* 绘制逻辑 */ }
}重要提示: 始终在事件中取消订阅以避免内存泄漏。
Unloaded4. 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
性能对比
| 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 |
| 方法 | 1万点耗时 | 适用场景 |
|---|---|---|
| Shape (Ellipse) | ~500ms | 元素数量<100的场景 |
| DrawingVisual | ~20ms | 1K-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 - 内存管理