简体   繁体   English

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

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM