on this page (jump to):

Dispatching to the UI Thread

When you are building rich client user interfaces you have to be vigilant not to lock up the user interface while performing intensive background tasks.

Using BackgroundWorker

One of the techniques available is to make use of the built in .NET BackgroundWorker object. This allows you to remove background processing from the UI thread. As you can see in the example below there are a lot of pieces that you need to make this work.

public partial class CustomerEdit : Form 
private readonly BackgroundWorker _backgroundWorker; 
 
public CustomerEdit() 
InitializeComponent(); 
_backgroundWorker = new BackgroundWorker(); 
_backgroundWorker.DoWork += DoSave; 
_backgroundWorker.RunWorkerCompleted += SaveCompleted; 
 
private void SaveCompleted(object sender, RunWorkerCompletedEventArgs e) 
lblStatus.Text = "Finished Saving"
 
private void btnSave_Click(object sender, EventArgs e) 
_backgroundWorker.RunWorkerAsync(); 
 
private void DoSave(object sender, DoWorkEventArgs doWorkEventArgs) 
var customerRepository = new CustomerRepository(); 
customerRepository.Save(BuildCustomerFromScreen()); 
 
private Customer BuildCustomerFromScreen() 
return new Customer(); 

To properly manage and interact with a BackgroundWorker process you need to hook the DoWork and RunWorkerCompleted events. You need to couple the code that should be run to the DoWorker event handler. The code to update the UI needs to be coupled to the RunWorkerCompleted event handler and, finally, you need to execute the BackgroundWorker object's RunWorkerAsync method to kick off the whole process.

As you can see, there are a lot of moving pieces in a very simple BackgroundWorker example. Here's how PostSharp simplifies this common coding scenario.

Adding background processing

  1. The first thing you need to understand is that you can write your code as if you had no thoughts of having any background processing occuring.
    public partial class CustomerEdit : Form 
    public CustomerEdit() 
    InitializeComponent(); 
     
    private void SaveCompleted() 
    lblStatus.Text = "Finished Saving"
     
    private void btnSave_Click(object sender, EventArgs e) 
    DoSave(); 
    SaveCompleted(); 
     
    private void DoSave() 
    var customerRepository = new CustomerRepository(); 
    customerRepository.Save(BuildCustomerFromScreen()); 
     
    private Customer BuildCustomerFromScreen() 
    return new Customer(); 
  2. Once you have written your code you will need to determine which piece of it should run in the background and in the UI threads. In this example the btnSave_Click method should execute in the background and the SaveCompleted method should execute in the UI thread.
    First, you should add the background processing to the btnSave_Click method. Adding background processing
  3. You will be prompted with a wizard to complete the process. Accept the first page. Page 1 of adding background processing
  4. If you have not yet added background processing to your project, PostSharp will download the Threading Pattern Library and add it for you. Page 2 of adding background processing
  5. Click Finish to complete the process. Page 3 of adding background processing
  6. When you look at your code you will see that only one thing has changed. The method you designated to run in the background is now decorated with the [BackgroundMethod] attribute.
    [BackgroundMethod] 
    private void btnSave_Click(object sender, EventArgs e) 
    DoSave(); 
    SaveCompleted(); 

Adding UI thread processing

Once you've added background processing to the button click, you will need a way to have the SaveCompleted method run on the UI thread. If you don't do this you will get an InvalidOperationException because setting the lblStatus.Text property is a cross threading operation.

UI Cross Threading error

Here's how you can fix this.

  1. Your code has encapsulated the UI thread interaction in the SaveCompleted method. Open the smart tag on that method and choose to execute the method in the object thread. This is tell PostSharp to configure this method to execute in the thread that the class containing the method is executing in. Adding object threading
  2. After selecting the smart tag option you will be returned to your code and you'll notice that the only change was the addition of the [DispatchedMethod] attribute to the SaveCompleted method.
    [DispatchedMethod] 
    private void SaveCompleted() 
    lblStatus.Text = "Finished Saving"

Now if you run your code you will no longer receive the InvalidOperationException and instead will see the label on the UI update. All of the Save functionality will occur in a separate thread which prevents the user interface from locking up while that is happening.



What to read next?

Background Thread Execution or back to Threading.