Mronzer
Mronzer

Reputation: 439

Proper way to cancel BackgroundWorker

Its my first time working on a wpf. An existing system has to process an excel file, now the requirement is, the excel file must have five comlumns. Here is the code that has to do the processing

  void InsertIDsNamesAndAddWorker_DoWork(object sender, DoWorkEventArgs e)
            {
              // read the excel file here
                int columns = xlWorkSheet.UsedRange.Columns.Count;
                if (columns == 5)
                {
                    //do your normal processing
                }
                else
                {
                    //if requirements are not met then display error message
                    System.Windows.MessageBox.Show("There must be five columns in this 
                   file", MessageBoxButton.OK, MessageBoxImage.Error);
                }
            }

Now this code does get into the else part, it however continues to other part which then displays an error message that says "done processing".

Here is the current code of the method that does the confirmation message

void InsertIDsNamesAndAddWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
            {
                ProgressBarValue = 100;
                StatusLable = "Done Processing.";
                if (System.Windows.MessageBox.Show("Done Processing.", "Status", MessageBoxButton.OK, MessageBoxImage.Information) == MessageBoxResult.OK)
                {
                    StatusLable = string.Empty;
                    ProgressBarValue = 0;
                }
            }

Now with me being new to the wpf technology, I realized that the hard-coded value of Statuslable is the one causing issues, so I went to set the ProgressBarValue to 100 if the the requirements were met and processing is done. I also set the ProgressBarValue to zero if the colums was not equal to 5. Here is the new code

void InsertIDsNamesAndAddWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
            {
                int count = ProgressBarValue;
                if (count != 100)
                {
                    StatusLable = string.Empty;
                    ProgressBarValue = 0;
                }
                else
                {
                    //ProgressBarValue = 100;
                    StatusLable = "Done Processing.";
                    if (System.Windows.MessageBox.Show("Done Processing.", "Status", MessageBoxButton.OK, MessageBoxImage.Information) == MessageBoxResult.OK)
                    {
                        StatusLable = string.Empty;
                        ProgressBarValue = 0;
                    }
                }

            }

My main question is, is this the right way though? is the any other way I can cancel the work if requirements are not met?

Upvotes: 0

Views: 514

Answers (2)

rene
rene

Reputation: 42444

Use the Result prorperty of the DoWorkEventArgs instance you get passed in DoWork:

void InsertIDsNamesAndAddWorker_DoWork(object sender, DoWorkEventArgs e)
{
    if (columns == 5)
    {
        //do your normal processing
        e.Result = true; // we're OK
    }
    else
    {
        //if requirements are not met then display error message
        System.Windows.MessageBox.Show("There must be five columns in this 
       file", MessageBoxButton.OK, MessageBoxImage.Error);

       e.Result = false; // something wrong
    }
}

and then in RunWorkerCompleted check the Result value and handle accordingly.

void InsertIDsNamesAndAddWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    // check if we're not cancelled or error-ed before checking the Result
    result = (!e.Cancelled && e.Error == null)? (bool) e.Result: false; // what is the outcome

    ProgressBarValue = 100;
    if (result) {
        StatusLable = "Done Processing.";
        if (System.Windows.MessageBox.Show("Done Processing.", "Status", MessageBoxButton.OK, MessageBoxImage.Information) == MessageBoxResult.OK)
        {
            StatusLable = string.Empty;
            ProgressBarValue = 0;
        }
    } 
    else 
    {
         StatusLable = "Error in Excel sheet";
    }
}

Notice that Result is of type object. You can put any instance of a type into it, even your own class, which might be needed if you want to return more fine grained details about what went wrong.

Upvotes: 2

Bryan
Bryan

Reputation: 91

The BackgroundWorker has a property called WorkerSupportsCancellation. If this is set to true, you've got another option to cancel the execution.

Whenever something wrong happens, you can call backgroundWorker.CancelAsync(), which will set a boolean to true (which is the CancellationPending property in the BackgroundWorker object).

You can then check, during execution, if the CancellationPending is true. If so, the worker should stop.

If the worker stops, it'll launch the RunWorkerCompleted event, which will end up in the handler for the method (if any is added).

This way of cancelling can be checked at all instructions, or at the start of a for loop (as in: for (int i = 0; (i < x) && worker.CancellationPending; i++) ;)

Hope this helps!

Upvotes: 2

Related Questions