开发者

Implement faster graphics operation on WPF Canvas

I am trying to build a simple graphics application in WPF C#. The purpose is to draw 10000*10000 rectangles of size 4 pixels each.

I have modified the OnRender method of the canvas to draw the rectangles. Drawings are performed for smaller number of rectangles (say 50*50 or 100*100 rectangles of 4 pixel each) but it is slowing down as I am increasing the no. of rectangles.

Following is my code:

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

            }
        }
    }

The above code takes more than a minute to draw 1000*1000 rectangles.

Is there any method to make this process faster? Is there any other开发者_如何学编程 thing I can use in place of this?

Thanks.


The purpose is to draw 10000*10000 rectangles of size 4 pixels each.

Do NOT draw them. That simple. This would be 40k to 40k pixels.

Most will not be visible. So they must not bee drawn. Basically only draw those that are visible in the canvas. When resizing or scrolling you repaint anyway, then do the same - only draw those that are visible.

Virtualization is the key to performance here. Take things out of the drawing loop as early as possible. Stuff not visible per definition does not need to be drawn at all.

Next alternative would be not to use a canvas. Try a bitmap. Prepare it on a separate thread, then draw this one at once.


You should try StreamGeometry then. http://msdn.microsoft.com/en-us/library/system.windows.media.streamgeometry.aspx

For complex geometries that don’t need to be modified after they are created, you should consider using StreamGeometry rather than PathGeometry as a performance optimization. StreamGeometry works like PathGeometry, except that it can only be filled via procedural code. Its odd name refers to an implementation detail: To use less memory (and less of the CPU), its PathFigures and PathSegments are stored as a compact byte stream rather than a graph of .NET objects.

Quoted from Adam Nathan's book WPF Unleashed.


You don't need to recreate the brush for each iteration of the loop, since they use the same color over and over:

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

This may speed up the loop a bit.


One more tip on top of what everyone already said, make sure the pens and brushes are frozen - if you create the brush call Freeze before using it (brushes from the Brushes class (Brushes.White) are already frozen).


The bitmap approach might speed up more - BitmapSource has a Create method that takes raw data either as an array or a pointer to unsafe memory. It should be a bit faster to set values in an array than drawing actual rectangles - however you have to checkout the pixelformats to set the individual pixels correctly.


Perhaps try overlaying the canvas with a VisualBrush.
To this visualBrush simply add the 4*4 rectangle and have it repeat in a tile mode. Alternatively you could just add the lines to it so that it doesnt overlap the edges of the rectangle... your choice :)

Your problem is in the creation of the brush... A test run indicated that this code

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

took 53 seconds to run. You are trying to create 100,000,000 brushes :) If it is patternable, use a patterned visual brush, if it is not patternable... perhapse look for another solution. The overhead of storing that many brushes in memory is in the Gigabytes

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜