0

I'm creating and application that needs to add and remove a lot of UIElement to a Canvas. Basically a Canvas contains a collection of UIElement and automatically renders/updates it on the screen depending what it contains.

In order to avoid having a tons of UIElements who overlap each others on the screen I prefer to add all of them on a secondary Canvas then create a Image from it (thanks to WritableBitmap). Finally I add this Image on my current Canvas. By allowing to have only few image on my Canvas I expect to have better performance. Unfortunately it seems I can't delete completely the WritableBitmap, even if I set it to null.

The following code illustrates it :

//My constructor
public  WP8Graphics() 
{
    //Here my collection DataBinded with the Canvas from the Mainpage
    this.UIElements = new ObservableCollection<UIElement>();
    //The secondary Canvas
    GraphicCanvas = new Canvas();
    GraphicCanvas.Height = MainPage.CurrentCanvasHeight;
    GraphicCanvas.Width = MainPage.CurrentCanvasWidth;
}


///This method can be hit thousand times, it basically create a rectangle 
public void fillRect(int x, int y, int width, int height)
{

// some code
// CREATE THE RECTANGLE rect

   GraphicCanvas.Children.Add(rect); // My secondary Canvas



   WriteableBitmap wb1 = new WriteableBitmap(GraphicCanvas, null);
   wb1.Invalidate();

   WriteableBitmap wb2 = new WriteableBitmap((int)MainPage.CurrentCanvasWidth, (int)MainPage.CurrentCanvasHeight);

  for (int i = 0; i < wb2.Pixels.Length; i++)
  {
       wb2.Pixels[i] = wb1.Pixels[i];
  }
  wb2.Invalidate();

  wb1 = null;

  Image thumbnail = new Image();
  thumbnail.Height = MainPage.CurrentCanvasHeight;
  thumbnail.Width = MainPage.CurrentCanvasWidth;
  thumbnail.Source = wb2;



  this.UIElements.Add(thumbnail);

}

After something like 24 WriteableBitmap created a OutOfMemoryException appears. I read many articles about this problem and in my case it seems the WriteableBitmap depends on my GraphicCanvas and remains because there still have a reference to it. I can't delete my Graphic Canvas nor set myImage source to null.

I have 2 question :

  • Is there another way to create an image from Canvas or a collection of UIElements ?
  • Is it possible to remove the reference who keeps that WriteableBitmap alive ?

I hope to be enough clear and easy to read.

Thank you for reading.

EDITED with atomaras suggestion, but still the same problem

WriteableBitmap wb1 = new WriteableBitmap(GraphicCanvas, null); This line still throws OutOfMemoryException.

Yann
  • 71
  • 8

1 Answers1

1

You need to copy the pixels of the original writeablebitmap (that will hold on to the GraphicsCanvas) to a new writeablebitmap.

Take a look at this great post http://www.wintellect.com/blogs/jprosise/silverlight-s-big-image-problem-and-what-you-can-do-about-it

Also why do you keep all of the writeablebitmaps in the UIElements collection? Wouldn't the latest one suffice? Cant you clear the UIElements collection right before adding the latest/new bitmap?

atomaras
  • 2,468
  • 2
  • 19
  • 28
  • Thank you for this. Unfortunately I've already tried this technique but it doesn't work. It seems that the `WritableBitmap` hold a reference to the `GraphicCanvas`. So I would need the `GraphicCanvas` to be deleted to broke that link. But I can't do this. Thank you – Yann Nov 07 '13 at 07:54
  • You need to remove the GraphicsCanvas from the UI in order for it to be garbage collected. But in order for the WriteableBitmaps to also stop keeping a reference to it you need copy them to a new WriteableBitmap and let the original die. Or you are just adding a LOT of elements in the GraphicsCanvas and your algorithm/solution is bound to reach the memory limit. In that case i'd look into rearchitecting the solution. – atomaras Nov 07 '13 at 08:00
  • The `GraphicCanvas` is not related to the UI, it's just a way to stock my `UIElement`. I bind my collection **UIElements** to the "real" Canvas. – Yann Nov 07 '13 at 08:07
  • I edited my solution but it seems there still a reference that avoid my `WriteableBitmaps` to be Garbage Collected. – Yann Nov 08 '13 at 04:10
  • You are creating thousands of Bitmaps (lots of memory) and adding them to the UI but it appears only the last one (in front) is visible. Why do you need the old ones? Don't you need just *one* bitmap that contains everything? – atomaras Nov 08 '13 at 08:05
  • I just need one "old" Bitmap to avoid flickering, I try to delete the first `WriteableBitmap` wb1 but I can't manage to do it. – Yann Nov 11 '13 at 03:08