c#-加快在WPF中将对象添加到Canvas的速度

我在WPF中使用了Canvas来绘制许多彩色矩形,但是添加它们时程序运行速度非常慢.我尝试了不同的选择,例如将它们添加到数组中并一次全部添加,并使用Image而不是Canvas来支付它们,但是它们似乎做得并不多.我有将代码引导到线程中的图形,但是由于C#规则,我必须在主线程中包含图形部分.我还应该注意,问题出在我的计算机上(它运行的是带有14GB DDR2 RAM的Intel Core i7).

这是添加矩形的代码.它已运行超过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);
    }

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

有什么建议么?

解决方法:

使用OnRender方法

我创建了一个继承Canvas的类,并重写OnRender方法以获取DrawingContext并使用它进行绘制.因此,在代码中,我没有将rects添加到画布上,而是添加到了新类的rect列表中,并调用了InvalidateVisual();.添加完成后,请使用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);
        }
    }
}

a

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

准备好后刷新,应在调度程序上进行

canvas.InvalidateVisual();

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

我也建议您添加一些缓存,以避免过度渲染

使用几何的解决方案

类级变量

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

该示例可以帮助您达到相同的目的.我还将尽快进行一些实验,以更快的方式获得所需的结果.

上一篇:使用Scipy.optimize method =’SLSQP’返回初始猜测


下一篇:codereview