【问题标题】:Implement faster graphics operation on WPF Canvas在 WPF Canvas 上实现更快的图形操作
【发布时间】:2010-10-25 05:56:18
【问题描述】:

我正在尝试在 WPF C# 中构建一个简单的图形应用程序。目的是绘制 10000*10000 个大小为 4 像素的矩形。

我已经修改了画布的 OnRender 方法来绘制矩形。绘图是针对较少数量的矩形(例如 50*50 或 100*100 矩形,每个 4 像素)执行的,但随着我增加数量而减慢。的矩形。

以下是我的代码:

  protected override void OnRender(DrawingContext dc)
    {
        base.OnRender(dc);

        FillCells(dc);

        if (_ShowGrids)
        {
            DrawGrid(dc); // draw grid lines
        }
    }
 void FillCells(DrawingContext dc)
    {

        int cellSize=4;

        for (int i = 0; i < MaxRow; i++)
        {
            for (int j = 0; j < MaxColumn; j++)
            {
                dc.DrawRectangle(GetRectBrush(i,j), GetRectPen(i,j), new Rect(j * cellSize , i * cellSize , cellSize - 1, cellSize - 1));

            }
        }
    }

以上代码绘制1000*1000个矩形需要一分钟多。

有什么方法可以加快这个过程吗?我可以用其他东西代替吗?

谢谢。

【问题讨论】:

  • 你考虑过使用visualBrush吗?
  • 不,我没有。你能给我一些视觉刷的例子吗?
  • 您是否将每个矩形的颜色存储在内存中?如果没有,GetRectBrush(i,j) 在做什么?
  • 是的,有一个二维颜色矩阵,用于存储特定坐标的矩形颜色。操纵颜色矩阵以绘制所需颜色的矩形。 GetRectBrush 返回该坐标矩形的solidcolorbrush。
  • 加载二维矩阵时...颜色设置占用多少内存?那是很多元素的地狱

标签: c# wpf canvas drawing


【解决方案1】:

目的是画10000*10000 每个大小为 4 像素的矩形。

不要画它们。就这么简单。这将是 40k 到 40k 像素。

大部分将不可见。所以他们不能被画出来。基本上只绘制那些在画布中可见的。调整大小或滚动时,无论如何都要重新绘制,然后做同样的事情 - 只绘制那些可见的。

虚拟化是性能的关键。尽早将事物从绘图循环中取出。根据定义不可见的东西根本不需要绘制。

下一个选择是不使用画布。试试位图。在单独的线程上准备它,然后一次绘制这个。

【讨论】:

  • 这是我认为提高性能的唯一方法。我也想过实现这种机制来绘制但无法计算画布的可见区域。我还在这里问了一个关于这个问题的问题,谷歌搜索但没有得到运气。
  • +1 @alxx。但是,当涉及到像 DataGrid 这样的控件或一些锯齿状的 Grid 控件时。绝对没问题。在某些情况下,它可能需要超过 100M。
  • @Avatar:在这种情况下,虚拟化也有同样的作用。
  • @Grozz Virtualization for Drawing context 没有实际意义:)
  • @Tom:谢谢,我已经实现了虚拟化来实现这一点,它就像“润滑脂轴承”一样工作。再次感谢!
【解决方案2】:

那你应该试试 StreamGeometry。 http://msdn.microsoft.com/en-us/library/system.windows.media.streamgeometry.aspx

对于不需要的复杂几何形状 在创建后进行修改, 你应该考虑使用 StreamGeometry 而不是 PathGeometry 作为一种表演 优化。 StreamGeometry 作品 像 PathGeometry,除了它可以 只能通过程序代码填写。 它奇怪的名字指的是一个 实施细节:少用 内存(以及更少的 CPU),它的 PathFigures 和 PathSegments 是 存储为紧凑的字节流,而不是 而不是 .NET 对象的图表。

引自 Adam Nathan 的《WPF Unleashed》一书。

【讨论】:

    【解决方案3】:

    您不需要为循环的每次迭代重新创建画笔,因为它们一遍又一遍地使用相同的颜色:

    SolidColorBrush blueBrush = new SolidColorBrush(Colors.Blue)
    SolidColorPen bluePen = new SolidColorPen(blueBrush)
    
    for (int i = 0; i < MaxRow; i++)
    {
        for (int j = 0; j < MaxColumn; j++)
        {
            dc.DrawRectangle(blueBrush, bluePen, 1), new Rect(j * cellSize , i * cellSize , cellSize - 1, cellSize - 1));
        }
    }
    

    这可能会加快循环速度。

    【讨论】:

    • 快一点但还是慢:(
    【解决方案4】:

    除了每个人已经说过的内容之外,还有一个提示,请确保笔和画笔已冻结 - 如果您在使用之前创建画笔调用 Freeze(来自 Brushes 类 (Brushes.White) 的画笔已被冻结)。

    【讨论】:

      【解决方案5】:

      位图方法可能会加快速度 - BitmapSource 有一个 Create 方法,该方法将原始数据作为数组或指向不安全内存的指针。 在数组中设置值应该比绘制实际矩形要快一些 - 但是您必须检查像素格式才能正确设置各个像素。

      【讨论】:

        【解决方案6】:

        也许尝试用 VisualBrush 覆盖画布。
        向这个 visualBrush 简单地添加 4*4 矩形并让它以平铺模式重复。或者,您可以只添加线条,使其不与矩形的边缘重叠......您的选择:)

        你的问题出在画笔的创建上……测试运行表明这段代码

        int limit = 10000 * 10000;
        var converter = new BrushConverter();
        for (int i = 0; i < limit; i++)
        {
            var blueBrush = converter.ConvertFromString("Blue") as Brush;
        }
        

        运行耗时 53 秒。您正在尝试创建 100,000,000 个画笔 :) 如果它是可图案化的,请使用带图案的视觉画笔,如果它不可图案化......也许寻找另一种解决方案。在内存中存储这么多画笔的开销以千兆字节为单位

        【讨论】:

        • 视觉画笔无法达到目的,因为矩形可能有不同的颜色。视觉画笔复制任何视觉元素。
        • 你是如何给矩形着色的?在您的示例中看起来它们都是蓝色的:)
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-12-09
        • 2022-01-23
        • 2011-05-24
        相关资源
        最近更新 更多