Slow, but gentle…
In real-life applications there are some operations that take more then “user-thinking” time (up to half a second for desktop applications, two seconds for web applications). Actually, this is a time before user gets nervous and tries to resubmit data or to perform other “destructive” actions. Typically, UI developers use some kind of progress indicator or just an animation that informs user about long-running operation and (optionally) provides progress information either as percent of job done, or number of items processed, or both.
Note that it’s just internal details of current implementation, things may change in future releases. Anyway, WD HTML client provides good enough implementation of “progress indicator” out of the box. However, there are some situations when this functionality is not enough or even not available at all.
What (the heck) I’m waiting for?
Let us imaging that you in fact have to display explanatory message when user invokes long-running operation. The algorithm is the following:
- Create TextView for message; bind its “visibility” property to context attribute of type Vsibility; either set text of TextView to some static value, or bind it to string context attribute.
- Create Timer control; bind its “enabled” property to context attribute of type boolean; set interval of timer to 1 (one second, the lowest possible value).
- Create and assign action for Timer OnTimeout event.
- In wdDoInit of view controller set value of “visibility” attribute (related to TextView) to WDVisibility.NONE and “enabled” (Timer) to false.
- Now, in action handler for Button or LinkToAction or whatever else you have, do the following:
- update text of TextView via context attribute if necessary;
- make TextView visible via context attribute;
- make Timer enabled (also via context attribute);
- optionally you may hide some other UI controls
Do not invoke long-running operation here!
- Finally, in OnTimeout action handler execute the following sequence:
- make TextView invisible again;
- disable Timer;
- execute long-running operation;
- if you performed 5.d, then revert back visibility changes for other controls.
From user point of view, this will result in following sequence: user clicks a button (or invoke action in some other way); then it sees message about long-running task; shortly progress indicator appears; finally, progress indicator is removed and result is shown.
The solution has two drawbacks. We force user to wait yet another second (timeout of Timer control), so apply this technique only when operation takes at least 5 seconds. Anyway, if it takes less then 5-3 seconds almost no one will read your message 🙂 Plus you must avoid placing a message at center of screen – it will be overlapped by indicator itself.
Ready! Steady! Go!
The second issue with built-in WD progress indicator is that it’s not invoked when application loads. Imaging a scenario, when application has to show user-specific dashboard (think about UWL inbox) on initial screen, so you make back-end call from wdDoInit of component controller. Loading of such dashboard requires selecting large set of items (probably from several back-end systems), filtering them, applying permissions etc. So application start time takes several seconds.
Also your customer and usability experts inside your company agree that such delay is acceptable, you noticed some unpleasant effect – the well-known and lovely WD loading indicator is not shown at all! What user sees for 3-5 seconds is just ugly blank screen! Es geht nicht.
The only way to fix WD behavior is to avoid loading data on startup. Seriously! My solution can be described as the following (again, Timer to the rescue):
- Create one additional view for main application window, kind of welcome screen.
- Make this view default on window, link it via plugs with “real” (or “main”) view
- On welcome screen place some “Loading…” message as TextView, plus application name, plus copyright notice, plus whatever you want (consult splash screen design of any desktop application) and enabled Timer control with one second delay. Again, make sure that any texts are not located at center of screen… for known reason. By the way, you may create empty view with single Timer control – you get extremely ascetic splash screen 😉
- In OnTimeout action handler of Timer, just fire plug to “real” view
- “Real” view calls public method of component controller that actually loads data. Important: this must be user-defined method, not wdDoInit hook!
How it works? User sees your welcome screen almost immediately. After short delay loading indicator appears. At this time Timer has already fired event, and server-side part of WD application is loading data. When data is available, indicator is removed and complete dashboard is shown.
My previous solution to this problem was a bit trickier. It requires re-start of application (do not worry, not in Visual Administrator, just redirect to another URL), usage of deprecated IFrame control and pair of Flash movie and animated GIF image. Here are the sources for this outdated implementation, use “Save as…” link command and rename to *.zip after download.