I used to think Canvas Apps are synchronous, since, after all, there are no callback functions, which means implementing a real async execution pattern would be a problem. As it turned out, there are at least a couple of situations where Canvas Apps are starting to behave in a very asynchronous way.
There is a “Select” function: https://docs.microsoft.com/en-us/powerapps/maker/canvas-apps/functions/function-select
And there is a “Concurrent” function: https://docs.microsoft.com/en-us/powerapps/maker/canvas-apps/functions/function-concurrent
Looking at the documentation for those two, you will get a hint of how Canvas Apps functions are, normally, evaluated:
Those two excerpts, bundled with the mere existence of the “chain” operator (“;”) are telling me that, normally, all functions in a chain are executed sequentially.
Except, of course, for those two above. Actually, “Concurrent” is also executed sequentially – it’s just that all those other functions within “Concurrent” won’t wait for each other.
“Select” turned out to be quite a different story, though.
I was having a problem with my app. As it often happens, I added a hidden button, so I could use that button to call the same “code” over and over again from different places. That seems to be a common workaround whenever we need to define our own “function” in Canvas Apps.
It usually works seamlessly – all I need to do is call Select(<ButtonName>) wherever we need to run that encapsulated code (while the user is on the same application screen).
However, the fact that “Select” only queues the target “OnSelect” for processing and does not execute it immediately makes all the difference in some situations.
Why did it bite me this time?
In my application I have a number of checkboxes per screen. Different users can open the same screen at the same time and start updating those checkboxes. I wanted to make sure that any change one user makes are presented to the other user at the earliest opportunity.
So, I figured, I’d do it this way:
- When the user changes something, I’d call “Select” for a hidden button
- In the “OnSelect” of that button, I’d re-read all values from the input controls, and I’ll use “Patch” to push changes to the CDS
- Then I’d re-read all data from CDS to capture any changes made by other users
- And, then, updated data would be displayed in the interface
Why does it matter that Select calls are not executing “OnSelect” immediately? Because what I ended up with is this:
I wanted to go with the least amount of efforts, so I figured I would go easy on the “OnChange” events, and I would just call “Select” there. In the Select, I would read values from the UI controls, I would patch the datasource, then I would reload data, and, then, I would update the UI with reloaded data.
Problem is, because of the queued nature of those “OnSelect” events, it may turn out that the data OnSelect would be using to update the UI would not really reflect the most recent changes made by the user, so some of those changes might be lost in the end.
Well, if you run into this issue, the only workaround I could think of is to put an overlay control (I used a label) on top of all other elements on my screen so that it would be hidden most of the times, but it would be displayed once OnSelected has started to prevent any user input:
We can easily manipulate the visibility of such control using a variable:
So, I just need to set that variable to true at the start of OnSelect, and, then, reset it to “false” once there is no more processing in the OnSelect.
Transparent effect can be achieved by using that last (“alpha”) parameter of the RGBA color – it indicates the opacity (in the range from 0 to 1, where 0 stands for “transparent”):