在 WPF 中加快向 Canvas 添加对象的速度 [英] Speed up adding objects to Canvas In WPF

查看:23
本文介绍了在 WPF 中加快向 Canvas 添加对象的速度的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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. 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. 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. I should also note that the problem isn't my computer (its running Intel Core i7 with 14GB DDR2 RAM).

这是添加矩形的代码.已运行超过 83,000 次.

This is the code that adds the rectangles. It is ran over 83,000 times.

    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);
    }

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

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.

有什么建议吗?

推荐答案

使用 OnRender 方法

我创建了一个继承 Canvas 的类,并覆盖了 OnRender 方法以获取 DrawingContext 并使用它进行绘制.所以在代码中,我不会将矩形添加到画布,而是添加到新类中的矩形列表,并在完成添加后使用 Dispatcher 调用 InvalidateVisual();.

I created a class inheriting Canvas, and override the OnRender method to get the DrawingContext and used it to draw. so in the code I dont add rects to the canvas but to the rect list in new class and call InvalidateVisual(); using Dispatcher once I am done with add.

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);
        }
    }
}

xml

<l:MyCanvas x:Name="canvas"/>

添加矩形

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();

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

This seems to be the fastest way to draw in WPF, you may not need to go till GDI+ or 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

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

Also I would advice you to add some caching to avoid rendering excessively

使用几何的解决方案

类级变量

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<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.

这篇关于在 WPF 中加快向 Canvas 添加对象的速度的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆