Using Background Process in WPF






4.60/5 (6 votes)
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.
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.
//first start the method with tread
System.Threading.ThreadStart ts = new System.Threading.ThreadStart(ExpansiveMethod);
System.Threading.Thread t = new System.Threading.Thread(ts);
t.Start();
protected void ExpansiveMethod()
{
//Very expansive call will go here...
//after the job is finished call method to update ui
MethodInvoker updaterMI = new MethodInvoker(UpdateChange);
this.BeginInvoke(UpdateChange);
}
protected void UpdateChange()
{
//again back to main ui thread
}
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()
{
//Call method to show wait screen
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)
{
//Call method to hide wait screen
}
void workertranaction_DoWork(object sender, DoWorkEventArgs e)
{
//My Expansive call will go here...
}
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
.
//delegate for our method of type void
public delegate void Process();
//and then use the dispatcher to call the method.
Process del = new Process(UpdateMyUI);
this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Background, del);
void UpdateMyUI()
{
//get back to main UI thread
}
For more reading about this Asynchronous Programming, please visit the references.