Illustration for my general question:
Working with WPF I’m often stuck with the following problem: before firing up a UI-heavy operation I turn on a visual feedback control for showing that the system is busy (some sort of a busy indicator); however the UI freezes without showing the busy indicator before it.
private void MyTree_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
this.MyBusyIndicator.IsBusy = true;
...
//then some UI related operation
...
this.MyBusyIndicator.IsBusy = false;
}
(I can’t move that time consuming operation to another thread, because it is the UI-thread related operation.)
Searching around for a possible solution or recommendation on solving such a problem, I read something about some WPF (or even .NET framework) UI updating specifics which is the main cause for this type of problem.
So my question:
What is those WPF (or .NET framework) UI updating mechanism specifics, which prevents UI to be updated in exactly the same sequence as it was defined in a code?
Is it specific to WPF only indeed?
What are possible solutions or workarounds?
Is it a real problem or maybe just a result of my poor understanding?
The problem isn’t specific to WPF – most UI frameworks behave the same way.
The problem here is that your UI won’t update until the UI thread can process messages. As long as you’re doing work (the UI related operations), the UI thread is busy and can’t process the messages required to redraw the screen. In this case, that means that busy indicator won’t redraw until after everything is completed.
The real solution here is to move the operations into a background thread. While you say that all of these are UI-thread related, there’s typically a way to separate out portions of this in WPF. The key is to think about the parts that are taking a long time, and move them, and only them, out. This typically means loading your data, but not setting it to the UI (ie: setting the bound property) until after it’s completely loaded and processed.
If that’s completely not possible, the only real option is to set your busy indicator, then use some mechanism to push the other work off until after the UI thread can process. This can be done by using Dispatcher.BeginInvoke to push the remaining work off until “later”, though it’s somewhat hackish to do. This would look like:
That being said, this isn’t always perfectly reliable, either – as you’re still locking your UI thread. Ideally, you should never block the UI, as it will prevent redraws from occurring correctly… A DispatcherTimer would work more reliably, but again, is really not a very good way to handle it.