加快在WPF中向Canvas添加对象的速度

我有一个Canvas ,我在WPF中使用它绘制许多彩色矩形,但程序在添加时运行速度非常慢。 我尝试了不同的选项,例如将它们添加到Array并一次添加它们并使用Image而不是Canvas来调度它们,但它们似乎没有做太多。 我在一个线程中有编码导致绘图,但由于C#规则,我必须在主线程中有绘图部分。 我还应该注意,问题不在于我的电脑(它运行的英特尔酷睿i7配备14GB DDR2内存)。

这是添加矩形的代码。 它跑了83,000多次。

  private void AddBlock(double left, double top, double width, double height, Brush color) { if (this.Dispatcher.Thread != Thread.CurrentThread) { this.Dispatcher.Invoke(new Action(this.AddBlock), left, top, width, height, color); return; } Rectangle rect = new Rectangle() { Width = width, Height = height, Fill = color, SnapsToDevicePixels = true }; this.canvas.Children.Add(rect); Canvas.SetLeft(rect, left); Canvas.SetTop(rect, top); } 

注意:正如我在下面的评论中所述,我想要一些允许它在单独的线程上运行的东西(即使它涉及使用P / Invoke),因为似乎没有一个可行的解决方案只使用C#和WPF 。

有什么建议?

使用OnRender方法

我创建了一个inheritanceCanvas的类,并重写OnRender方法以获取DrawingContext并使用它来绘制。 所以在代码中我不添加rects到canvas,但添加到新类的rect列表并调用InvalidateVisual(); 完成添加后使用Dispatcher。

 class MyCanvas:Canvas { public class MyRect { public Rect Rect; public Brush Brush; } public List rects = new List(); protected override void OnRender(System.Windows.Media.DrawingContext dc) { base.OnRender(dc); for (int i = 0; i < rects.Count; i++) { MyRect mRect = rects[i]; dc.DrawRectangle(mRect.Brush, null, mRect.Rect); } } } 

XAML

  

添加rects

 private void AddBlock(double left, double top, double width, double height, Brush color) { canvas.rects.Add(new MyCanvas.MyRect() { Brush = color, Rect = new Rect(left, top, width, height) }); } 

准备好后刷新,应该在调度员上进行

 canvas.InvalidateVisual(); 

这似乎是在WPF中绘制的最快方式,你可能不需要去GDI +或pinvoke。 在我的系统测试期间,原始代码花费大约500 ms来渲染830 rects渲染,并且几何体花费大约400毫秒来渲染相同的内容,而这种方法在不到100 ms渲染了83,000 rects

另外我建议你添加一些缓存以避免过度渲染

使用几何的解决方案

类级变量

 GeometryGroup gGroup; 

使用以下代码准备

 DrawingBrush dBrush= new DrawingBrush(); gGroup = new GeometryGroup(); GeometryDrawing gDrawing = new GeometryDrawing(Brushes.Red, null, gGroup); dBrush.Drawing = gDrawing; Canvas.Background = dBrush 

然后你的代码

 private void AddBlock(double left, double top, double width, double height, Brush color) { if (this.Dispatcher.Thread != Thread.CurrentThread) { this.Dispatcher.Invoke(new Action(this.AddBlock), left, top, width, height, color); return; } //color need to figure out as it is added in GeometryDrawing //currently Brushes.Red defined earlier gGroup.Children.Add(new RectangleGeometry(new Rect(left, top, width, height))); } 

此示例可以帮助您实现相同的目标。 我也会尽快做一些实验,以更快的速度获得你想要的结果。