I recently received a question from a person we will refer to as “Hingle McCringleberry”, that was related to an old post I did back in 2011 showing how to use the Extended WPF Toolkit’s BusyIndicator control, back when I was the project owner. In that post, I showed how to use the BackgroundWorker to create a multi threaded application and report progress back to the UI. Of course it worked like a charm. Well, a lot of things have changed since then, and there are new APIs available to perform multithreading in WPF applications. So, Hingle McCringleberry decided to use these new APIs, specifically the async/await APIs, to modify the old sample. Should be straight forward right? Well, yes and no.
The problem was that even though the multithreading code was working perfectly, the UI would freeze during the process, although it should remain responsive. I mean, that’s why we do multithreading in the first place, right. So let’s takes a look at the sample and see if we can identify the problem.
Here is the view:
Here is the code behind:
At first glance everything appears like it should work just fine. When we click the “Start Process” button, we generate 1,000,000 items, add them to a list, and then set the ItemsSource of the ListBox to the items we generated. As you can see, we are using the IProgress<T> which makes it extremely easy to report progress to the UI. So as items are created, we are calculating the percentage done, and updating a TextBlock and a ProgressBar to our end-user so they know how much longer they have until the process is complete. But, if you run the app as it is, you will notice that when you click the “Start Process” button, the UI freezes until the operation is completed.
When everything is done, the the ProgressBar and TextBlock suddenly go to 100%. This is not what we want. We need the UI to remain responsive, and increment the values so that the end-user can see the actual progress of the operation. So what’s going on here?
You’re flooding your UI with too many updates!
That’s right, you are pushing way too many update to the UI. “Hingle McCringleberry” didn’t realize he was pushing 1,000,000 individual updates to the UI within milliseconds. So fast, that the UI didn’t have time to repaint. Since messages that say “go update this” have a higher priority that a render/paint message, it never gets around to re-rendering /repainting the UI.
So how do we fix it? Easy! You just have to control how many updates you are sending. I mean, you don’t have to update the UI every singlle time. You just need to give your end-user a really close estimate of completion. So just add a simple modification to your code.
double percentage = (double)i / maxRecords;
In this case, we said I will update the UI every 1500 items being generated. The result is night and day. Check it out:
Now, that’s much better!
That wraps up this post. Be sure to check out the source code, and start playing with it. As always, feel free contact me on my blog, connect with me on Twitter (@brianlagunas), or leave a comment below for any questions or comments you may have.