Using OnRender method
I created a class inheriting Canvas, and override the OnRender method to get the DrawingContext and used it to draw. so in the code I dont add rects to the canvas but to the rect list in new class and call InvalidateVisual();
using Dispatcher once I am done with add.
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);
}
}
}
xaml
<l:MyCanvas x:Name="canvas"/>
to add the rects
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) });
}
refresh when ready, should be made on dispatcher
canvas.InvalidateVisual();
This seems to be the fastest way to draw in WPF, you may not need to go till GDI+ or pinvoke. During tests in my system original code took approx 500 ms
to render 830 rects
and geometry took approx 400 ms to render the same, where as this approach rendered 83,000 rects
in less then 100 ms
Also I would advice you to add some caching to avoid rendering excessively
A solution using geometry
class level variables
GeometryGroup gGroup;
prepare using the following code
DrawingBrush dBrush= new DrawingBrush();
gGroup = new GeometryGroup();
GeometryDrawing gDrawing = new GeometryDrawing(Brushes.Red, null, gGroup);
dBrush.Drawing = gDrawing;
Canvas.Background = dBrush
then comes your code
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)));
}
This sample may help you achieve the same. I'll also do some experiment soon to get your desired result in a much faster way.