WPF Performance: Displaying thousands of Paths / Shapes on a Canvas

kitsune picture kitsune · Sep 29, 2009 · Viewed 8.7k times · Source

I'm currently developing a visualization tool that draws WPF shapes such as paths, ellipses etc. on a Canvas. I've already implemented a virtualized approach where Shapes are being destroyed and created on the fly depending on their visibility. However, even with only like 600 ellipses visible, the application seems to struggle.

What are my options to speed things up? I'm thinking rendering grouped Shapes (let's say 500 at a time) as transparent bitmaps and only painting these on the Canvas. But I don't know whether that's a good idea... From what I gather this requires some sort of hack, if transformations were applied:

     VisualBrush shapeBrush = new VisualBrush(shape);  

     DrawingVisual drawingVisual = new DrawingVisual();  
     DrawingContext drawingContext = drawingVisual.RenderOpen();  

     using (drawingContext)  
     {  
        drawingContext.DrawRectangle(shapeBrush, null, new Rect(new Point(0, 0), new Point(actualWidth, actualHeight)));  
     }  
     renderTarget.Render(drawingVisual);  

What about using a big WritableBitmap? Would that be another approach?

Answer

Eamon Nerbonne picture Eamon Nerbonne · Sep 29, 2009

WPF under the covers works with drawings and geometries - when you say you're working with shapes, are these actual UIElements? Such elements are quite a bit more heavy-weight. If you use just basic (preferably stream-) geometries to draw drawings, you'll get the best performance in my experience.

I managed to get up to around 10000 dots with a reasonable framerate with that approach, but anything more complex than a dot starts slowing things down (say, round dots or even just rectangles). Still, basic geometries and basic drawings are the way to go if you want to avoid as much WPF overhead as possible.

A Writeable bitmap is clearly eventually faster, but that means rending all those shapes yourself, or, caching the result bitmap if it's mostly static. Also, you'll generally want to apply transformations before rendering to bitmap rather than applying them to the rendered bitmap itself.