[英]Speed up adding objects to Canvas In WPF
I have a Canvas
that I am using in WPF to draw many colored rectangles to but the program is running really slow when they are being added. 我有一个
Canvas
,我在WPF中使用它绘制许多彩色矩形,但程序在添加时运行速度非常慢。 I have tried different options, such as adding them to an Array
and adding them all at once and using a Image
instead of a Canvas to dispay them, but they didn't seem to do much. 我尝试了不同的选项,例如将它们添加到
Array
并一次添加它们并使用Image
而不是Canvas来调度它们,但它们似乎没有做太多。 I have the coding leading up the drawing in a thread, but because of C# rules, I have to have the drawing part in the main thread. 我有一个代码在一个线程中引导绘图,但由于C#规则,我必须在主线程中有绘图部分。 I should also note that the problem isn't my computer (its running Intel Core i7 with 14GB DDR2 RAM).
我还应该注意,问题不在于我的电脑(它运行的英特尔酷睿i7配备14GB DDR2内存)。
This is the code that adds the rectangles. 这是添加矩形的代码。 It is ran over 83,000 times.
它跑了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<double, double, double, double, Brush>(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);
}
NOTE: As I stated in a comment below, I would like something that allows it to run on a seperate thread (even if it involves working with P/Invoke) as there doesn't seem to a viable solution to just using C# and WPF. 注意:正如我在下面的评论中所述,我想要一些允许它在单独的线程上运行的东西(即使它涉及使用P / Invoke),因为似乎没有一个可行的解决方案只使用C#和WPF 。
Any suggestions? 有什么建议?
Using OnRender method 使用OnRender方法
I created a class inheriting Canvas, and override the OnRender method to get the DrawingContext and used it to draw. 我创建了一个继承Canvas的类,并重写OnRender方法以获取DrawingContext并使用它来绘制。 so in the code I dont add rects to the canvas but to the rect list in new class and call
InvalidateVisual();
所以在代码中我不添加rects到画布,但添加到新类的rect列表并调用
InvalidateVisual();
using Dispatcher once I am done with add. 完成添加后使用Dispatcher。
class MyCanvas:Canvas
{
public class MyRect
{
public Rect Rect;
public Brush Brush;
}
public List<MyRect> rects = new List<MyRect>();
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 XAML
<l:MyCanvas x:Name="canvas"/>
to add the rects 添加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) });
}
refresh when ready, should be made on dispatcher 准备好后刷新,应该在调度员上进行
canvas.InvalidateVisual();
This seems to be the fastest way to draw in WPF, you may not need to go till GDI+ or pinvoke. 这似乎是在WPF中绘制的最快方式,您可能不需要直到GDI +或pinvoke。 During tests in my system original code took approx
500 ms
to render 830 rects
and geometry took approx 400 ms to render the same, where as this approach rendered 83,000 rects
in less then 100 ms
在我的系统测试期间,原始代码花费大约
500 ms
来渲染830 rects
并且几何体花费大约400毫秒来渲染相同的内容,其中这种方法在不到100 ms
渲染了83,000 rects
Also I would advice you to add some caching to avoid rendering excessively 另外我建议你添加一些缓存以避免过度渲染
A solution using geometry 使用几何的解决方案
class level variables 类级变量
GeometryGroup gGroup;
prepare using the following code 使用以下代码准备
DrawingBrush dBrush= new DrawingBrush();
gGroup = new GeometryGroup();
GeometryDrawing gDrawing = new GeometryDrawing(Brushes.Red, null, gGroup);
dBrush.Drawing = gDrawing;
Canvas.Background = dBrush
then comes your code 然后你的代码
private void AddBlock(double left, double top, double width, double height, Brush color)
{
if (this.Dispatcher.Thread != Thread.CurrentThread)
{
this.Dispatcher.Invoke(new Action<double, double, double, double, Brush>(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)));
}
This sample may help you achieve the same. 此示例可帮助您实现相同目标。 I'll also do some experiment soon to get your desired result in a much faster way.
我也会尽快做一些实验,以更快的速度获得你想要的结果。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.