Updating code that used the Graphics property

Prior to 2018r3 Window and Canvas both had a Graphics property that you could access and draw to. This was deprecated in 2011 because it had significant performance issues on all platforms. The preferred way to draw your graphics since 2011 has been to use the DesktopWindow.Paint or DesktopCanvas.Paint event handlers and the supplied parameter g As Graphics.

Starting with 2018r3, this Graphics property was removed from Window and Canvas so if you had code that was still relying on it, that code will no longer compile. Here are some tips on how you can migrate your code to use the Paint event handlers and tell the Canvas to update with a call to Refresh.

Simple drawing

If your code was simple and just drawing a Picture to the Graphics property, then you would just move the code to the Paint event handler. For example, this code is drawing a picture:

Canvas1.Graphics.DrawPicture(MyPic, 0, 0)

Where that code existed, you would tell it to redraw Canvas1:


And then in the DesktopCanvas.Paint event handler you would draw the picture:

g.DrawPicture(MyPic, 0, 0)

More advanced drawing

If your code was doing more advanced drawing to the Graphics property then you will need to do more substantial changes to your code. Since you ideally want to do all the drawing in the Paint event handler you may need to use a separate means to store what was being updated (such a properties or a class) and then in the Paint event handler use these values to do the drawing.

So say you had code in a MouseDown that was drawing a point on the Canvas when the mouse was clicked like this:

Canvas1.Graphics.FillRectangle(X, Y, 5, 5)

You would now create properties to store the X and Y values from the MouseDown event:

LastClickX As Integer
LastClickY As Integer

In MouseDown you would now save the values to the properties and tell the Canvas to update when the mouse was clicked:

LastClickX = X
LastClickY = Y

Lastly you would put code in DesktopCanvas.Paint to draw the point:

g.FillRectangle(LastClickX, LastClickY, 5, 5)

Although the above is recommended, you may find that making all the changes needed is more than you want to change. Another technique you can use is to do the drawing in an offscreen picture and then draw the picture in the Canvas. With this technique you create a Picture property for your drawing:

MyDrawing As Picture

You then initialize it to the size you want using the DesktopWindow.BitmapForCaching method (so that it is HiDPI compatible):

MyDrawing = Self.BitmapForCaching(500, 500)

And then everywhere where you were drawing directly to Graphics you now draw to your Picture property and tell the Canvas to update. So instead of:

Canvas1.Graphics.DrawingColor =Color.RGB(255, 0, 0)
Canvas1.Graphics.DrawLine(0, 0, 100, 100)

your code would look like this:

MyDrawing.Graphics.DrawingColor =Color.RGB(255, 0, 0)
MyDrawing.Graphics.DrawLine(0, 0, 100, 100)

And in the Paint event for Canvas1:

g.DrawPicture(MyDrawing, 0, 0)

Do not use Graphics outside of Paint event lifetime

Related to this is another thing to keep in mind. Do not use this Graphics object outside the lifetime of the Paint event. You can certainly pass the Graphics parameter from the Paint event to other methods, but you should not keep a reference of it in a property or elsewhere. When the Paint event eventually completes, this Graphics object is no longer valid and the copy you've saved in a property also becomes invalid. Attempting to use a saved Graphics object outside of the Paint event's lifetime may raise an exception in future versions of Xojo.

See also