C# 加快在WPF中将对象添加到画布的速度

C# 加快在WPF中将对象添加到画布的速度,c#,wpf,optimization,canvas,C#,Wpf,Optimization,Canvas,我有一个Canvas,我在WPF中使用它来绘制许多彩色矩形,但是当它们被添加时,程序运行得非常慢。我尝试过不同的选择,比如将它们添加到数组中,然后一次将它们全部添加,并使用图像来显示它们,而不是使用画布,但它们似乎没有起到多大作用。我在一个线程中有引导绘图的代码,但是由于C#规则,我必须在主线程中有绘图部分。我还应该指出,问题不在于我的计算机(它运行的是带有14GB DDR2 RAM的Intel Core i7) 这是添加矩形的代码。它运行了83000多次 private void Ad

我有一个
Canvas
,我在WPF中使用它来绘制许多彩色矩形,但是当它们被添加时,程序运行得非常慢。我尝试过不同的选择,比如将它们添加到
数组中,然后一次将它们全部添加,并使用
图像来显示它们,而不是使用画布,但它们似乎没有起到多大作用。我在一个线程中有引导绘图的代码,但是由于C#规则,我必须在主线程中有绘图部分。我还应该指出,问题不在于我的计算机(它运行的是带有14GB DDR2 RAM的Intel Core i7)

这是添加矩形的代码。它运行了83000多次

    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);
    }
private void AddBlock(双左、双顶、双宽、双高、画笔颜色)
{
if(this.Dispatcher.Thread!=Thread.CurrentThread)
{
this.Dispatcher.Invoke(新操作(this.AddBlock)、左、上、宽、高、颜色);
返回;
}
矩形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并使用它来绘制。因此,在代码中,我不会将rect添加到画布中,而是添加到新类中的rect列表中,并调用
invalidateevisial()完成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);
        }
    }
}
准备就绪后,应在dispatcher上进行刷新

canvas.InvalidateVisual();
这似乎是使用WPF的最快方法,您可能不需要等到GDI+或pinvoke。在我的系统中进行测试期间,原始代码大约花费了
500 ms
来渲染
830个矩形
,几何体大约花费了400 ms来渲染相同的矩形,其中,与此方法一样,在
100 ms的时间内渲染
83000个矩形

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

使用几何体的解决方案

类级变量

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)));
}
private void AddBlock(双左、双顶、双宽、双高、画笔颜色)
{
if(this.Dispatcher.Thread!=Thread.CurrentThread)
{
this.Dispatcher.Invoke(新操作(this.AddBlock)、左、上、宽、高、颜色);
返回;
}
//在几何绘图中添加颜色时,需要计算颜色
//当前为笔刷。前面定义了红色
添加(新矩形几何体(新矩形(左、上、宽、高));
}

此示例可能会帮助您实现相同的目标。我还将很快做一些实验,以更快地获得您想要的结果。

您是否尝试使用几何体而不是矩形?@ub3rst4r-您可以使用轻量级drawingVisual在画布上绘制对象。参考代码让你开始。这不起作用,因为(a)我需要块是一种颜色,(b)它仍然很慢。我想要的是在线程上运行但能与WPF一起工作的东西(即使它涉及P/Invoke)。好的,给我一些时间,我能为你做点什么吗。更新了我的答案以使用OnRender方法,它非常快。我只需调整线程,使它能与该类一起工作,现在它很快就会更新!谢谢
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)));
}