Search code examples
c#wpfbackgroundworker

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?


Solution

  • 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.