WPF applications often need to call time consuming methods or processes. The time consuming methods or processes can be, huge time consuming calculations or perhaps a web service call. In case of WPF specially XBAP (WPF browser application) which runs on remote client machines browser. These sort of calls can make your user interface unresponsive. I am working with WPF for more than four months. Lot of things come into way and are dealt with nicely. Well in this post, I am going to share a simple trick for avoiding unresponsiveness of user interface. We have already used this technique in many cases in our application, but this is for WPF.
The "Thread & Invoke"
BackgroundWorker
is a very smooth and useful tool for our purpose of making more responsive UI (user interface). Before discussing more about BackgroundWorker
, let's take a flash back of legacy technique (which is pretty smart) implementation of making more responsive UI. Previously I used threading for implementing such kind of UI smoothness. What I did is to create a background thread and call expansive operation on that thread. When the job is finished, use the "MethodInvoker
" method to let know the UI thread that the job is finished. And this model is called asynchronous model. And this is quite a smart model and the rest of the models are based on this approach. Here is a quick code snippet for demonstrating the technique.
System.Threading.ThreadStart ts = new System.Threading.ThreadStart(ExpansiveMethod);
System.Threading.Thread t = new System.Threading.Thread(ts);
t.Start();
protected void ExpansiveMethod()
{
MethodInvoker updaterMI = new MethodInvoker(UpdateChange);
this.BeginInvoke(UpdateChange);
}
protected void UpdateChange()
{
}
The "Background Worker"
Okay, it's time to use the BackgroundWorker
. An amazing thing about background worker is, it's simple to use. First, let's see what a background worker is. "BackgroundWorker
" is a class under "System.ComponentModel
" which executes an operation on a separate thread. Which is introduced from .NET Framework 2.0. Things are again pretty simple just like thread. All you have to do is instantiate a BackgroundWorker
and subscribe its events, and call the "RunWorkerAsync()
" method. Let's put a code snippet. Since we are programmers, we understand code better.
void MyMethodToCallExpansiveOperation()
{
BackgroundWorker workertranaction = new BackgroundWorker();
workertranaction.DoWork += new DoWorkEventHandler(workertranaction_DoWork);
workertranaction.RunWorkerCompleted += new RunWorkerCompletedEventHandler(
workertranaction_RunWorkerCompleted);
workertranaction.RunWorkerAsync();
}
void workertranaction_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
}
void workertranaction_DoWork(object sender, DoWorkEventArgs e)
{
}
As you can see in the above code, I have subscribed to event "DoWork
" (which is the main function) and "RunWorkerCompleted
". In dowork
event handler, we will put our expansive time consuming operations, as the name implies RunWorkerCompleted
event is fired when the work is finished . BackgroundWorker
also has "ProgressChanged
" event which is used to let the main UI thread know how much work is completed.
The "Dispatcher"
In few cases, the BackgroundWorker
needs to access the main UI thread. In WPF, we can use "Dispatcher
" which is a class of "System.Windows.Threading
" and a delegate to access the main thread. First of all, we have to declare a delegate for our candidate methods, and then use the delegate to call the method using Dispatcher
. Dispatcher
has few thread priorities and you can use various priorities from DispatcherPriority enum
. "Send
" has the highest priority in DispatcherPriority
.
public delegate void Process();
Process del = new Process(UpdateMyUI);
this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Background, del);
void UpdateMyUI()
{
}
For more reading about this Asynchronous Programming, please visit the references.
References