Skip to content

WinForm TaskRun vs BackgroundWorker

DUONG Phu-Hiep edited this page Nov 13, 2015 · 1 revision

http://blog.stephencleary.com/2013/05/taskrun-vs-backgroundworker-round-1.html

Basic use

private void button1_Click(object sender, EventArgs e)
{
    var bgw = new BackgroundWorker();
    bgw.DoWork += (_, __) =>
    {
        Thread.Sleep(1000);
    };
    bgw.RunWorkerCompleted += (_, __) =>
    {
        MessageBox.Show("Hi from the UI thread!");
    };
    bgw.RunWorkerAsync();
}

vs

private async void button2_Click(object sender, EventArgs e)
{
    await Task.Run(() =>
    {
        Thread.Sleep(1000);
    });
    MessageBox.Show("Hi from the UI thread!");
}

Error handling

private void button1_Click(object sender, EventArgs e)
{
    var bgw = new BackgroundWorker();
    bgw.DoWork += (_, __) =>
    {
        Thread.Sleep(1000);
        throw new InvalidOperationException("Hi!");
    };
    bgw.RunWorkerCompleted += (_, args) =>
    {
        if (args.Error != null)
            MessageBox.Show(args.Error.Message);
    };
    bgw.RunWorkerAsync();
}

vs

private async void button2_Click(object sender, EventArgs e)
{
    try
    {
        await Task.Run(() =>
        {
            Thread.Sleep(1000);
            throw new InvalidOperationException("Hi!");
        });
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
}

Returning Result

private void button1_Click(object sender, EventArgs e)
{
    var bgw = new BackgroundWorker();
    bgw.DoWork += (_, args) =>
    {
        Thread.Sleep(1000);
        args.Result = 13;
    };
    bgw.RunWorkerCompleted += (_, args) =>
    {
        var result = (int)args.Result;
        MessageBox.Show("Result is " + result);
    };
    bgw.RunWorkerAsync();
}

vs

private async void button2_Click(object sender, EventArgs e)
{
    var result = await Task.Run(() =>
    {
        Thread.Sleep(1000);
        return 13;
    });
    MessageBox.Show("Result is " + result);
}

Cancellation

private BackgroundWorker _bgw;
private void button1_Click(object sender, EventArgs e)
{
    _bgw = new BackgroundWorker();
    var bgw = _bgw;
    bgw.WorkerSupportsCancellation = true;
    bgw.DoWork += (_, args) =>
    {
        for (int i = 0; i != 100; ++i)
        {
            if (bgw.CancellationPending)
            {
                args.Cancel = true;
                return;
            }
            Thread.Sleep(100);
        }
    };
    bgw.RunWorkerCompleted += (_, args) =>
    {
        if (args.Cancelled)
            MessageBox.Show("Cancelled.");
        else
            MessageBox.Show("Completed.");
    };
    bgw.RunWorkerAsync();
}
private void cancelButton1_Click(object sender, EventArgs e)
{
    if (_bgw != null)
        _bgw.CancelAsync();
}

vs

private CancellationTokenSource _cts;
private async void button2_Click(object sender, EventArgs e)
{
    _cts = new CancellationTokenSource();
    var token = _cts.Token;
    try
    {
        await Task.Run(() =>
        {
            for (int i = 0; i != 100; ++i)
            {
                token.ThrowIfCancellationRequested();
                Thread.Sleep(100);
            }
        });
        MessageBox.Show("Completed.");
    }
    catch (OperationCanceledException)
    {
        MessageBox.Show("Cancelled.");
    }
}
private void cancelButton2_Click(object sender, EventArgs e)
{
    if (_cts != null)
        _cts.Cancel();
}

Progress

private void button1_Click(object sender, EventArgs e)
{
    var bgw = new BackgroundWorker();
    bgw.WorkerReportsProgress = true;
    bgw.DoWork += (_, args) =>
    {
        for (int i = 0; i != 100; ++i)
        {
            bgw.ReportProgress(0, "Stage " + i);
            Thread.Sleep(100);
        }
    };
    bgw.ProgressChanged += (_, args) =>
    {
        label1.Text = (string)args.UserState;
    };
    bgw.RunWorkerCompleted += (_, args) =>
    {
        label1.Text = "Completed.";
    };
    bgw.RunWorkerAsync();
}

vs

private async void button2_Click(object sender, EventArgs e)
{
    var progressHandler = new Progress<string>(value =>
    {
        label2.Text = value;
    });
    var progress = progressHandler as IProgress<string>;
    await Task.Run(() =>
    {
        for (int i = 0; i != 100; ++i)
        {
            if (progress != null)
                progress.Report("Stage " + i);
            Thread.Sleep(100);
        }
    });
    label2.Text = "Completed.";
}

Conclusion

private BackgroundWorker _bgw;
private void button1_Click(object sender, EventArgs e)
{
  var fail = checkBox1.Checked;
  _bgw = new BackgroundWorker();
  var bgw = _bgw;
  bgw.WorkerSupportsCancellation = true;
  bgw.WorkerReportsProgress = true;
  bgw.DoWork += (_, args) =>
  {
    for (int i = 0; i != 100; ++i)
    {
      bgw.ReportProgress(0, i + "%");
      if (bgw.CancellationPending)
      {
        args.Cancel = true;
        return;
      }
      Thread.Sleep(100);
    }
    if (fail)
      throw new InvalidOperationException("Requested to fail.");
    args.Result = 13;
  };
  bgw.ProgressChanged += (_, args) =>
  {
    label1.Text = (string)args.UserState;
  };
  bgw.RunWorkerCompleted += (_, args) =>
  {
    if (args.Cancelled)
    {
      label1.Text = "Cancelled.";
    }
    else if (args.Error == null)
    {
      var result = (int)args.Result;
      label1.Text = "Completed: " + result;
    }
    else
    {
      label1.Text = args.Error.GetType().Name + ": " + args.Error.Message;
    }
  };
  bgw.RunWorkerAsync();
}
private void cancelButton1_Click(object sender, EventArgs e)
{
  if (_bgw != null)
    _bgw.CancelAsync();
}

vs

private CancellationTokenSource _cts;
private async void button2_Click(object sender, EventArgs e)
{
  var fail = checkBox1.Checked;
  _cts = new CancellationTokenSource();
  var token = _cts.Token;
  var progressHandler = new Progress<string>(value =>
  {
    label2.Text = value;
  });
  var progress = progressHandler as IProgress<string>;
  try
  {
    var result = await Task.Run(() =>
    {
      for (int i = 0; i != 100; ++i)
      {
        if (progress != null)
          progress.Report(i + "%");
        token.ThrowIfCancellationRequested();
        Thread.Sleep(100);
      }
      if (fail)
        throw new InvalidOperationException("Requested to fail.");
      return 13;
    });
    label2.Text = "Completed: " + result;
  }
  catch (OperationCanceledException)
  {
    label2.Text = "Cancelled.";
  }
  catch (Exception ex)
  {
    label2.Text = ex.GetType().Name + ": " + ex.Message;
  }
}
private void cancelButton2_Click(object sender, EventArgs e)
{
  if (_cts != null)
    _cts.Cancel();
}