DesktopCanvas Invalidate gone

If you convert an application for API2, you may run up against some now erroneous lines of code.

One will be CanvasInstance.Invalid which is allowed for the old Canvas but not allowed for the new DesktopCanvas. As best I have been able to find, this is dropped without comment. One of the puzzling aspects to me of the transition to API2 is the lack of documentation about what was the thinking behind changes that were made and a basic list of those changes.

In any case, DesktopCanvasInstance.Invalid is a Method that does not exist. So if you do a global update of a project to API2, all the lines that used to work as CanvasInstance.Invalid are now marked as errors in their converted version to DesktopCanvasInstance.Invalid.

My question(s) are these:
Can you just convert all these lines to DesktopCanvasInstance.Refresh and not worry about it?
Is there something that you are losing with this strategy?
Should you be using an alternative approach?
Why was the Method Invalidate thought to be worthwhile in API1, but not thought to be worth preserving in API2?

The answer is YES :wink:

1 Like

i think the new Method Name is Refresh :wink:
just faced this last week

.Refresh([immediately as Boolean = False])

1 Like

Yes, and as I wrote in another forum, I think it’s a xojo mistake as old code MyCanvas.Refresh did refresh immediately in API1 but without any change it is as if we have written MyCanvas.invalidate

1 Like

I see - I think

The “old” Refresh had no parameter to indicate whether you wanted it to occur immediately or when convenient. So the “old” Refresh was always immediate. There was a separate command, Invalidate, for refreshing when convenient.

The “new” Refresh has a boolean parameter - Immediately. If immediately is set to False then it is equivalent to the old method Invalidate. If immediately is set to True, then it is equivalent to the “old” Refresh.


Oh, this is scary.
Traditionally refresh was synchronous and should be avoided for 99% of the time. While invalidate was coalesced, meaning you could call it 100 times in a method, but it would only fire once at the end of the run loop.

Personally I would have gone with a different name (less negative connotations), maybe something like needsUpdating or needsDrawing.

Does the new "Refresh’ allow a simple rectangle to be passed, so we can mark only the area that has actually changed.

DesktopUIControl.Refresh(x As Integer, y As Integer, width As Integer, height As Integer, [immediately as Boolean = False])
New in 2021r3
Supported for all project types and targets.
Redraws the portion specified of the contents of the control the next time the OS redraws the control or immediately if True is passed.

I think just to be on the safe side and reduce conversion (at least for me), I might create my own .invalidate function that works like the original, ensuring the Apple API I trust is being called.

1 Like

FWIW, the refresh rectangles no longer seem to do anything on macOS, as in, they never make it to the paint event. In our investigations, it appears that this was an intentional change by Apple, so you shouldn’t rely on it to speed up your drawing. The answer I found last month was that if you need this functionality, you should implement it yourself.


It still works as expected (at least in my tests), so only that rectangle is actually refreshed (you may need layer-backed views), however yes, you no longer get passed the actual rect that was updated, so you need to manage that yourself.

Yet the function for getting the rects is not marked as deprecated or anything in the documentation. Trips people up every once in a while.

It’s tricky because they do work on Windows & Linux, and we only found out about the issue on macOS just before the holidays. As an event, we can’t easily replace it so we’ll probably just add a note in the docs about them not getting populated on macOS.

My biggest worry in all this is…Is the new Refresh equal to the old Invalidate or the old Refresh ?

If it is the old Refresh then I am worried on performance.


My biggest worry in all this is…Is the new Refresh equal to the old Invalidate or the old Refresh ?

Refresh(True) = previous Refresh
Refresh(False) = previous Invalidate

1 Like


But both Refresh and Invalidate had optional parameter “eraseBackground as Boolean”

Difference in the 2 was that one marks area as dirty while the other refreshes. And of course in any decent performing system then 99% of the time you want to mark as dirty and not force refresh.

1 Like

I see it in the docs you are right the new parameter is indeed immediately as Boolean.

So I suppose the lost functionality is only eraseBackground true or false, which was always a bit suspicious one and probably did not work same across platforms

1 Like

Yes, but previous Refresh without parameter (True) which was for the erase background is considered in the new API as the previous Invalidate.
Someone who update his code and who didn’t use the parameter True or False to erase background or not in API1 can do a search/replace:
.Refresh → .Refresh(True)
.Invalidate → .Refresh(False) or Simply .Refresh as default is false.

1 Like

That may have been my fault.
I am sure I filed a Feedback, but I don’t always any more (and at wrong 'puter to check). I did tweet about it back in Feb 2021.

It is a bit crap, as it’s a feature that Apple had often promoted in WWDC videos for optimizing your applications performance. I get the feeling that it doesn’t work as it should and Apple know it, but don’t care enough to invest resources in fixing it. Like validating App Store receipts from a Mac application.

Edit: I did file a feedback case in Feb 2021 on the matter. <>