A user interacts with the application by scrolling lists, clicking active form elements, typing in form fields, etc. Some user actions trigger events that run our source code. There are cases when my code wants to talk to a user - give him some information or ask a question. Like in this case, for example, when there are not enough products left. So, let’s see how we can communicate with a user from the source code.
Here is an example for us. Working with the Companies catalog, I noticed that I could click Refresh the map when no physical address is specified, in which case my current location is shown. Let’s tell a user that they forgot to specify the address and then cancel the refresh procedure. So, before refreshing the map, we need to make sure this attribute is not empty. The attribute has the string type, so I’m going here and here is the function I need. OK. Let’s open the refresh-is-clicked event handler and drop the function right here. So, this is my condition and here is the simplest way of informing a user. Now I’m just exiting the event handler without refreshing the map, and this is what the message looks like. It just pops up at the bottom of the current form like this. Let’s see what else have we got in the messaging department.
Wow. Looks like we have the entire arsenal here. This is the Message procedure we just used, and this is the guy I want us to try next. OK. Let’s replace Message with DoMessageBox, and this is what we’ve got. Now the message is in its own small form, and a user cannot click anywhere on the screen but at this OK button. Looks and works good but there is a catch.
This small window is a modal one. It means that the entire application is now stopped and waiting for a user to click this OK button. This is how our ancestors - the ancient programmers - used to make sure that the user has read the message or answered a question. Back then all applications were single-threaded, and stopping the entire application was the most natural and straightforward way of getting answers from a user. These times are long gone, and now the single-threaded applications are rare artifacts - like punched cards or floppy disks. Now everything is multi-threaded, a lot of things are going on on the background, so we cannot afford just stopping everything and waiting for a user to click OK. I was able to make it work for the desktop client by changing this setting from its default value. But even now it won’t work for all the clients the Platform supports. If I try the same in the web client, this is what I get because my Chrome (like almost every modern browser) does not support modal windows anymore. So, what do we do instead? This is what.
As you can see, there are pairs of methods with similar names except for the prefixes. The "Do" methods open modal windows, while the "Show" methods do the same but without modality. And this is what the difference looks like at the runtime. This is the modal "Do" version of the MessageBox. I’m setting a breakpoint here, running the application, clicking Refresh the map, and we are at the breakpoint. Let’s execute this line, and here is what happened. My source code execution has been completely stalled. It does nothing but waits for the user’s input in this modal window. And only after the user clicks OK, the application moves on to the next line of my code.
OK, let’s try the non-modal version of the message box. This method has an optional first parameter I don’t need, so I’m adding a comma here. OK. Running the app, clicking Refresh the map and we are at the breakpoint again. Executing the lineтАж And the application’s just continuing to work as if nothing happened. At the same time a user still cannot click anywhere, but on this OK button, so from their perspective, nothing has changed. Except, now it works anywhere including all the browsers. But from the developer’s perspective, the difference is huge. Especially when you need to fork the execution depending on the user’s answer to some question which we ask using DoQueryBox or ShowQueryBox methods.
Here is another example for us. Check out this new cool piece of functionality I’ve just implemented behind the scene. So, these are my cashiers. And this is the cashier form that now knows how to combine a first and a last name to get the full name automatically, just like this. It works without bothering a user until they change the full name manually. After that the form cannot afford to silently replace the user’s version with an automatically generated one. So it does this. It asks user’s permission to replace the full name. And if the permission is granted, it proceeds and regenerates the full name like this. Let me show you how it’s implemented.
So, this is the Cashiers catalog item form. I use the Description attribute to store the cashier’s full name. I also added this FullNameIsChanged boolean flag that turns on whenever a user changes the Description value manually. When the first or the last name is changed, this procedure is called. It checks the flag, and if it’s on, asks a user for the permission to change the full name.
The second parameter here can be a value of this system enumeration, containing the most commonly used buttons combinations, or any other set of buttons you manually pick yourself. And of course, this DoQueryBox opens a modal window, so it works like this. I’m raising the flag by changing the full name, then I’m changing the last name, and we are at the breakpoint. Executing this DoQueryBox guy, and the application is completely stalled. Nothing’s going on until a user answers the question. The user says yes, and we are back in business. The code is running, so now we can process the answer and do what we need to do. You see the problem here? I cannot afford using Do because of its modality.
But I also cannot just replace it with ShowQueryBox, because the code won’t stop executing at this line. It will move on to the next line long before a user can see, let alone answer the question. So how on Earth am I supposed to catch and process the user’s answer without the modality? This is how. I’m right-clicking to the DoQueryMessage call, selecting Refactor, Legacy calls and Convert call. Let’s agree to the default name of whatever Platform asks us to name, andтАж Wow. What just happened? OK, let’s see. Changing the full name. Changing the last name. We are at the breakpoint. The question is asked, and the application just moves on minding its own business until everything is executed. Meanwhile, a user takes his time, makes his mind and clicks Yes here, and all of a sudden we are back in Designer inside of this FillFullNameEnd procedure the Platform created for us. But how did we get here?
This is how. The first parameter of the ShowQueryBox procedure defines what method to call and where to call it from after a user answers the question asked. So, this is how we get here. Now we can check the user’s answer and fill out the cashier’s full name if the answer is yes. This is how we talk to a user from the source code.