BackgroundWorker is a class that was introduced with in Windows Forms 2.0 to simplify executing work on background threads allowing UI developers to easily keep their UIs responsive by not tying up the UI thread. It’s a tool that was very useful and if you don’t already know then you’ll probably be very pleased to find out that you can still use BackgroundWorker in WPF. This is because BackgroundWorker uses AsyncOperationManager which in turn uses SynchronizationContext to marshall work. In Windows Forms AsyncOperationManager gets a WindowsFormsSynchronizationContext class from the Forms application that derives from the SynchronizationContext class and uses it for marshalling. When using WPF a DispatcherSynchronizationContext is fetched by AsyncOperationManager which allows for easy marshalling of calls to background threads using BackgroundWorker.
Below is sample code for a simple form that will take your name as input and the write out “Hello ” as output after a 5 second delay. If you run the application you will see that it is responsive during the delay and that you can resize and move the windows around as you should be able to when doing work on background threads. The demo also shows how to pass a value (your name) from the UI to the background thread.
Xaml
<Window x:Class="WpfBackgroundWorker.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Window1" Height="300" Width="300"> <StackPanel> <TextBlock x:Name="Header" >Enter your name</TextBlock> <TextBox x:Name="InputTextBox" /> <Button x:Name="DoWorkButton" Content="Do work" Click="DoWorkButton_Click" /> <TextBlock x:Name="OutputTextBlock" /> </StackPanel> </Window>
Code behind
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.ComponentModel;
using System.Threading;
namespace WpfBackgroundWorker
{
/// <summary>
/// Interaction logic for Window1.xaml
/// </summary>
public partial class Window1 : Window
{
private BackgroundWorker _backgroundWorker;
public Window1()
{
InitializeComponent();
// Will use DispatcherSynchronizationContext
_backgroundWorker = new BackgroundWorker();
// Wire up event handlers
_backgroundWorker.DoWork
+= new DoWorkEventHandler(_backgroundWorker_DoWork);
_backgroundWorker.RunWorkerCompleted
+= new RunWorkerCompletedEventHandler(_backgroundWorker_RunWorkerCompleted);
}
void _backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
string result = (string)e.Result;
if (e.Cancelled)
{
OutputTextBlock.Text = "Cancelled";
}
else if (e.Error != null)
{
OutputTextBlock.Text = "Exception: " + e.Error.Message;
}
else
{
OutputTextBlock.Text = result;
}
}
void _backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
// Wait 5 seconds to simulate long running work
Thread.Sleep(5000);
// Assign the result to the Result property
// of the DoWorkEventArgs
// object. This is will be available to the
// RunWorkerCompleted eventhandler.
e.Result = "Hello " + e.Argument.ToString();
}
private void DoWorkButton_Click(object sender, RoutedEventArgs e)
{
if (string.IsNullOrEmpty(InputTextBox.Text))
{
MessageBox.Show("You must enter a name.");
return;
}
// Do work on background thread
_backgroundWorker.RunWorkerAsync(InputTextBox.Text);
}
}
}
Tags: BackgroundWorker, DispatcherSynchronizationContext, SynchronizationContext, Threading, WPF, WPF 3.5
[...] This post was mentioned on Twitter by MSExpression and MSExpression, AJDev.net. AJDev.net said: RT @MSExpression: Ruan blogged: Using BackgroundWorker with #WPF – http://bit.ly/4w9w2G – #msexp [...]