Using BackgroundWorker to update status

I’ve been working on an application the past few days that iterates through directories and processes files within those directories.  I was looking for a good way to keep the user informed of progress, and I decided that using System.ComponentModel.BackgroundWorker was my best solution.

Here’s some relevant code for how I used UserState to keep the user updated of the progress:

namespace BackgroundWorkerSample
{
    public partial class Main : Form
    {
        #region Form Callbacks
        private void btnCancel_Click(object sender, EventArgs e)
        {
            // Let the user know the cancel is processing
            btnCancel.Text = "Cancelling...";
            btnCancel.Enabled = false;

            // Ask the background worker to cancel its process
            if ((null != _FileProcessingWorker) && (_FileProcessingWorker.IsBusy))
            {
                _FileProcessingWorker.CancelAsync();
            }
        }

        private void btnProcess_Click(object sender, EventArgs e)
        {
            // Set up the background worker
            _FileProcessingWorker = new BackgroundWorker();
            _FileProcessingWorker.WorkerReportsProgress = true;
            _FileProcessingWorker.WorkerSupportsCancellation = true;

            // Add the events needed for the background worker
            _FileProcessingWorker.DoWork += new DoWorkEventHandler(_FileProcessingWorker_DoWork);
            _FileProcessingWorker.ProgressChanged += new ProgressChangedEventHandler(_FileProcessingWorker_ProgressChanged);
            _FileProcessingWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(_FileProcessingWorker_RunWorkerCompleted);
            
            // Get the directory to process
            string BasePath = lblDirectoryName.Text;
            DirectoryInfo MyDirectory = new DirectoryInfo(BasePath);
            DirectoryInfo[] MySubDirectories = MyDirectory.GetDirectories();

            // Collect statistics for the progress bar
            int SubDirectoryCount = MySubDirectories.GetLength(0);
            MyProgressBar.Minimum = 0;
            MyProgressBar.Step = 1;
            MyProgressBar.Maximum = SubDirectoryCount;
            MyProgressBar.Value = MyProgressBar.Minimum;
            _LastCounter = 0;

            // Instantiate the background worker and pass the file list
            _FileProcessingWorker.RunWorkerAsync(MySubDirectories);
        }
        #endregion

        #region File processing methods and events
        private void _FileProcessingWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            // Cast the EventArgs to the expected type
            DirectoryInfo[] MySubDirectories = (DirectoryInfo[])e.Argument;

            // Loop through the subdirectories
            for (int i = 0; i < MySubDirectories.GetLength(0); i++)
            {
                DirectoryInfo MySubDirectory = MySubDirectories[i];
                // Keep track of the current directory
                string CurrentDirectory = "Current Directory: " + MySubDirectory.Name;

                // Loop through the matching files
                foreach (FileInfo MyFile in MySubDirectory.GetFiles("*.txt"))
                {
                    // See if the user has requested cancellation
                    if (_FileProcessingWorker.CancellationPending)
                    {
                        e.Cancel = true;
                        return;
                    }
                    // Keep track of the current file
                    string CurrentFile = "Current File: " + MyFile.Name;
                    // Create an object to report the status via UserState
                    string[] CurrentStatus = new string[2];
                    CurrentStatus[0] = CurrentDirectory;
                    CurrentStatus[1] = CurrentFile;
                    // Raise the ProgressChanged event to allow reporting of status
                    _FileProcessingWorker.ReportProgress(i, CurrentStatus);

                    // Do the needed processing on the file
                    Thread.Sleep(500);
                }
            }
        }

        private void _FileProcessingWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            // Update the progress bar and status labels when the background worker reports progress
            // Cast the EventArgs to the expected type
            if (typeof(string[]) == e.UserState.GetType())
            {
                string[] StatusMsg = (string[])e.UserState;
                if (2 == StatusMsg.GetLength(0))
                {
                    // Update the status labels
                    lblCurrentDirectory.Text = StatusMsg[0];
                    lblStatus.Text = StatusMsg[1];
                }
            }

            // See if the percentage completion needs to be updated
            if (e.ProgressPercentage > _LastCounter)
            {
                _LastCounter = e.ProgressPercentage;
                // Increment the progress bar
                MyProgressBar.PerformStep();
            }
        }

        private void _FileProcessingWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            // Keep the display of the last directory and file processed
            lblCurrentDirectory.Text = lblCurrentDirectory.Text.Replace("Current", "Last");
            lblStatus.Text = lblStatus.Text.Replace("Current", "Last");
        }
        #endregion
    }
}

You can download a complete project here.

Advertisements

2 thoughts on “Using BackgroundWorker to update status

  1. I think this works on a single main form. My requirement is different: The file name being read must be viewed from a Childform.showDialog(). Can this be done?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s