Saturday 21 August 2010

Updating UI Elements using ProgressChanged event of BackgroundWorker

As you probably know, the only thread which can update a UI element, such as a Label, is the main thread which created that UI element.

In my previous article, I wrote about an approach to update the UI elements using the Dispatcher object of the UI element. Here I’d like to show you another approach which is to use ProgressChanged event of the BackgroundWorker:

public partial class Window1 : Window
{
BackgroundWorker aWorker = new BackgroundWorker();

public Window1()
{
InitializeComponent();
aWorker.WorkerSupportsCancellation = true;
aWorker.WorkerReportsProgress = true;
aWorker.DoWork += aWorker_DoWork;
aWorker.RunWorkerCompleted += aWorker_RunWorkerCompleted;
aWorker.ProgressChanged += new ProgressChangedEventHandler(aWorker_ProgressChanged);
}

/// <summary>
/// Handles the ProgressChanged event of the aWorker control. this runs on the main thread
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="System.ComponentModel.ProgressChangedEventArgs"/> instance containing the event data.</param>
void aWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
UpdateLabel(Int32.Parse(e.UserState.ToString()));
}

/// <summary>
/// Handles the DoWork event of the aWorker control.
/// This runs in a new thread
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="System.ComponentModel.DoWorkEventArgs"/> instance containing the event data.</param>
private void aWorker_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
for (int i = 0; i <= 500; i++)
{
Thread.Sleep(100);

if (aWorker.CancellationPending)
{
e.Cancel = true;
return;
}
aWorker.ReportProgress(0, i);
}
}

private void aWorker_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
{
if (!(e.Cancelled))
Label2.Content = "Run Completed!";
else
Label2.Content = "Run Cancelled!";
}

private void UpdateLabel(int i)
{
Label1.Content = "Cycles: " + i.ToString();
}

private void btnStart_Click(object sender, RoutedEventArgs e)
{
aWorker.RunWorkerAsync();
}

private void btnCancel_Click(object sender, RoutedEventArgs e)
{
aWorker.CancelAsync();
}
}

Notes:
  • There are 3 easy steps you need to take to enable this:

    • Set WorkerReportsProgress property

    • Subscribe to ProgressChanged event

    • Call ReportProgress() method from the worker thread

No comments: