I have several custom controls based on a canvas that I am updating for dark mode on Mojave. Id like to have these controls (classes) be aware when Mojave switches between light and dark mode, to save calling each instance of this class from App.AppearanceChanged - basically to refresh/invalidate them so that they use new colours that have been set in App properties. Is there a way to do this?
I’ve added a Feature Request for exactly those kind of situations : <https://xojo.com/issue/53778>
It would be much more convenient than it is now
Well… the Canvas-based Controls will get the .Paint Event fired after AppearanceChanged.
So you could add a private Property/Flag to your custom Canvas subclasses, and check if the current IsDarkMode value you get in the .Paint Event is the same as you’ve used in the last Paint-Event. If not - then something is different now
The .Paint event will get fired if the Appeareance (Dark/Light Mode) has changed. So basically you just need to check IsDarkMode in the Paint-Event and use the appropriate Colors. The above is just an idea if you want to know if it has changed - but that you only need to know if you for example have “dynamically cached Pictures” that you would need to rebuild then.
[quote] @Jürg Otter Well… the Canvas-based Controls will get the .Paint Event fired after AppearanceChanged.
So you could add a private Property/Flag to your custom Canvas subclasses, and check if the current IsDarkMode value you get in the .Paint Event is the same as you’ve used in the last Paint-Event. If not - then something is different now :)[/quote]
The only issue I see with this now that I’ve looked into it a bit more is that the user could change the Accent or Highlight colour in System Prefs which triggers AppearanceChanged, but if all you are doing in the Paint event handler is checking IsDarkMode then this change won’t get reflected in the UI. I might see if I can create a string version of the system appearance settings that can be stored and then compared each time a paint handler is called. Or that might be too much overhead in which case I’ll go with Christian’s suggestion.
And again: in most cases you don’t need to know if the Appearance has changed in a Canvas.Paint Event. If you’re then doing the drawing, it will pick up the “current” Colors. That’s really only required if you need to “destroy/rebuild” some cached ressources.
Oh, I’ve just had one more thought
You could also just create a global property in a global module: AppearanceChangedCounter.
Increment it in App.AppearanceChanged, and have your Canvas.Paint's privately remember the “last used-for-painting counter value”. If the global one’s different - then Appearance has changed in between.
Ive thought about how to explain this in a way that doesnt sound condescending; I am not trying to be condescending, but I want to illustrate my experiences with things like this (and the Retina transition).
Ideally you want to be in place where you dont need to worry about what theme the user is using. Apple provide a whole bunch of color constants. They dont actually match the colors they use for building controls, but with some experimentation you should be able to find ones that are close enough for you to use.
Theres a couple of sample projects out there listing the various colors you can use.
In my experience with these things; the more complicated solutions you have to devise, the more youre fighting the system and eventually youll lose, leading to even more frustration with Cooked Apple.