Acelerar la adición de objetos a Canvas en WPF

Tengo un Canvas que estoy usando en WPF para dibujar muchos rectangularjs de colores, pero el progtwig se está ejecutando realmente lento cuando se agregan. He intentado con diferentes opciones, como agregarlas a una Array y agregarlas todas al mismo tiempo y usar una Image lugar de un canvas para mostrarlas, pero no parecían hacer mucho. Tengo la encoding que conduce el dibujo en un hilo, pero debido a las reglas de C #, tengo que tener la parte de dibujo en el hilo principal. También debo señalar que el problema no es mi computadora (está ejecutando Intel Core i7 con 14 GB de RAM DDR2).

Este es el código que agrega los rectangularjs. Se ejecutó más de 83,000 veces.

  private void AddBlock(double left, double top, double width, double height, Brush color) { if (this.Dispatcher.Thread != Thread.CurrentThread) { this.Dispatcher.Invoke(new Action(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); } 

NOTA: Como dije en un comentario a continuación, me gustaría algo que le permita ejecutarse en un hilo separado (incluso si implica trabajar con P / Invoke) ya que no parece haber una solución viable para simplemente usar C # y WPF .

¿Alguna sugerencia?

Usando el método OnRender

Creé una clase que heredaba Canvas y anulé el método OnRender para obtener DrawingContext y lo usé para dibujar. entonces en el código no agrego rects al canvas pero a la lista rect en una nueva clase y llamo a InvalidateVisual(); usando Dispatcher una vez que haya terminado con agregar.

 class MyCanvas:Canvas { public class MyRect { public Rect Rect; public Brush Brush; } public List rects = new List(); 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

  

agregar las rectas

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

actualizar cuando esté listo, debe hacerse en el despachador

 canvas.InvalidateVisual(); 

Esta parece ser la manera más rápida de dibujar en WPF, puede que no necesite ir hasta GDI + o pinvoke. Durante las pruebas en mi sistema, el código original tardó aproximadamente 500 ms en renderizar 830 rects y la geometría tardó aproximadamente 400 ms en renderizar igual, mientras que con este enfoque se 83,000 rects en menos de 100 ms

También te aconsejaría que agregases algo de almacenamiento en caché para evitar renderizar en exceso

Una solución que usa geometría

variables de nivel de clase

 GeometryGroup gGroup; 

prepara usando el siguiente código

 DrawingBrush dBrush= new DrawingBrush(); gGroup = new GeometryGroup(); GeometryDrawing gDrawing = new GeometryDrawing(Brushes.Red, null, gGroup); dBrush.Drawing = gDrawing; Canvas.Background = dBrush 

luego viene tu código

 private void AddBlock(double left, double top, double width, double height, Brush color) { if (this.Dispatcher.Thread != Thread.CurrentThread) { this.Dispatcher.Invoke(new Action(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))); } 

Esta muestra puede ayudarlo a lograr lo mismo. También haré algo de experimento pronto para obtener el resultado deseado de una manera mucho más rápida.