From BackgroundWorker, to TPL, to Async


I’m back to blogging again.  More on that later…

In any client UI code (WinForms/WPF/Silverilght/WinRT), it’s always a good practice to do as much in the background as possible so you aren’t blocking the UI thread.  “In the old days,” the BackgroundWorker was my best friend when I needed to executed some code in the background.  Along came the Task Parallel Library (TPL), and I moved to using it over Background worker.  Now we have the async enhancements coming soon.  Here’s a comparison of the approaches.

Consider this UI:

   1:  <Window x:Class="WpfApplicationComparingBackground_v_Task.MainWindow"
   2:    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   3:    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   4:    Title="MainWindow"
   5:    Height="350"
   6:    Width="525">
   7:    <StackPanel>
   8:      <TextBlock x:Name="Text1" />
   9:      <TextBlock x:Name="Text2" />
  10:      <TextBlock x:Name="Text3" />
  11:    </StackPanel>
  12:  </Window>

And this code behind:

   1:  using System;
   2:  using System.ComponentModel;
   3:  using System.Threading;
   4:  using System.Threading.Tasks;
   5:  using System.Windows;
   6:   
   7:  namespace WpfApplicationComparingBackground_v_Task
   8:  {
   9:      public partial class MainWindow : Window
  10:      {
  11:          public MainWindow()
  12:          {
  13:              InitializeComponent();
  14:   
  15:              Loaded += MainWindow_Loaded;
  16:          }
  17:   
  18:          void MainWindow_Loaded(object sender, RoutedEventArgs e)
  19:          {
  20:              BackgroundWorkerExample();
  21:              TaskContinueWithExample();
  22:              AsyncCtpExample();
  23:          }
  24:   
  25:          private void BackgroundWorkerExample()
  26:          {
  27:              var bWorker = new BackgroundWorker();
  28:   
  29:              bWorker.DoWork += (sender, args) =>
  30:              {
  31:                  // Mimic Some Long Running work
  32:                  Thread.Sleep(TimeSpan.FromSeconds(5));
  33:                  args.Result = "Using BackgroundWorker";
  34:              };
  35:   
  36:              bWorker.RunWorkerCompleted += (sender, args) =>
  37:              {
  38:                  Text1.Text = args.Result.ToString();
  39:              };
  40:   
  41:              bWorker.RunWorkerAsync();
  42:          }
  43:   
  44:          private void TaskContinueWithExample()
  45:          {
  46:              var uiThreadTaskScheduler = TaskScheduler.FromCurrentSynchronizationContext();
  47:   
  48:              Task<string>.Factory.StartNew(() =>
  49:              {
  50:                  // Mimic Some Long Running work
  51:                  Thread.Sleep(TimeSpan.FromSeconds(5));
  52:   
  53:                  return "Using TPL";
  54:              }).ContinueWith(task =>
  55:              {
  56:                  Text2.Text = task.Result;
  57:              }, uiThreadTaskScheduler);
  58:          }
  59:   
  60:          private async void AsyncCtpExample()
  61:          {
  62:              var response = await Task<string>.Factory.StartNew(() =>
  63:              {
  64:                  // Mimic Some Long Running work
  65:                  Thread.Sleep(TimeSpan.FromSeconds(5));
  66:   
  67:                  return "Using Async CTP";
  68:              });
  69:   
  70:              Text3.Text = response;
  71:          }
  72:      }
  73:  }

Although the TaskContinueWithExample() isn’t much less code than the BackgroundWorkerExample(), it just feels better to me and reads top to bottom which I think is a bit easier to grok.  Of course, the AsyncCtp() example is the least amount of and most readable code.  These three methods accomplish the same goal, but isn’t it nice that the framework / language abstractions have evolved to the simplicity / beauty of AsyncCtpExample()?

Comments (0)

Skip to main content