Using a BackgroundWorker Thread to Run a Task in a Windows Form

Using a BackgroundWorker Thread to Run a Task in a Windows Form

Problem:

From within a Windows Forms  application, when a button is clicked the program would disable the button and then perform the task associated with the button from within the button  Click event handler. If this is a long-running task then the UI thread can become unresponsive and start queuing events, even for those such as a mouse click on the disabled button. When the button is enabled again the queued events would be run and the event handler code would be invoked again in error.

Solution:

This demo shows one possible method of avoiding this scenario by executing a long-running task by creating a BackgroundWorker thread and running the task separately from the main UI thread. In this manner the UI thread is free to keep processing events and the BackgroundWorker thread can report its progress and also be canceled if need be.                     

The zipped up Visual Studio 2019 solution for BackgroundWorkerDemo is attached to this article.

      $set ilusing"System.Threading"
      $set ilusing"System.ComponentModel"
      *---------------------------------------------------------------------------*
      *                      BackgroundWorkerDemo                                 *
      *                                                                           *
      *  The original problem that a customer had was from within a Windows Forms *
      *  application, when a button was clicked they would disable the button and *
      *  then perform the task associated with the button from within the button  *
      *  Click event handler. If this was a long-running task then the UI would   *
      *  become unresponsive and starting queuing events, even for those such as  *
      *  a mouse click on the disabled button. When the button was enabled again  *
      *  the queued events would be run and the event handler would be run again. *
      *
      *  This demo shows one possible method of avoiding this scenario by execut- *
      *  ing a long-running task by creating a BackgroundWorker thread and running*
      *  the task separately from the main UI thread. In this manner the UI thread*
      *  is free to keep processing events and the BackgroundWorker thread can re-*
      *  port its progress and also be canceled if need be.                       *
      *---------------------------------------------------------------------------*
       class-id BackgroundWorkerDemo.Form1 is partial
                 inherits type System.Windows.Forms.Form.
       working-storage section.
                    
       method-id NEW.
       procedure division.
           invoke self::InitializeComponent
           *> tell the backgroundWorker task to report its progress by calling the
           *> associated event handler which can update the UI
           set backgroundWorker1::WorkerReportsProgress = true
           *> allow the backgroundWorker task to be canceled
           set backgroundWorker1::WorkerSupportsCancellation = true
           *> set initial state of the Start and Canel buttons
           set btnStart::Enabled to true
           set btnCancel::Enabled to false
           goback.
       end method.

       method-id BackgroundWorker1_DoWork final private.
       procedure division using by value sender as object e as type System.ComponentModel.DoWorkEventArgs.
            declare worker as type BackgroundWorker = sender as type BackgroundWorker
            perform varying i as binary-long from 1 by 1 until i > 10
               if worker::CancellationPending = true
                  set e::Cancel = true 
                  goback
               else
                  *> Perform a time consuming operation and report progress.
                  invoke type Thread::Sleep(1000)
                  invoke worker::ReportProgress(i * 10)
               end-if
           end-perform

       end method.

       method-id BackgroundWorker1_RunWorkerCompleted final private.
       procedure division using by value sender as object e as type System.ComponentModel.RunWorkerCompletedEventArgs.
           if e::Cancelled = true
               set lblPercent::Text = "Task Canceled!"
           else
              if e::Error not = null
                 set lblPercent::Text = "Error: " & e::Error::Message
              else
                 set lblPercent::Text = "Done!"
              end-if
           end-if
            
           set btnStart::Enabled to true
           set btnCancel::Enabled to false
           
       end method.

       method-id BackgroundWorker1_ProgressChanged final private.
       procedure division using by value sender as object e as type System.ComponentModel.ProgressChangedEventArgs.
           set lblPercent::Text = e::ProgressPercentage::ToString & "%"
       end method.

       method-id btnStart_Click final private.
       procedure division using by value sender as object e as type System.EventArgs.

           set btnStart::Enabled to false
           set btnCancel::Enabled to true
           if backgroundWorker1::IsBusy not = true
               *>  Start the asynchronous operation.
               *>  This will invoke the method BackgroundWorker1_DoWork
               invoke backgroundWorker1::RunWorkerAsync
           end-if

       end method.

       method-id btnCancel_Click final private.
       procedure division using by value sender as object e as type System.EventArgs.

           if backgroundWorker1::WorkerSupportsCancellation = true
               *> Cancel the asynchronous operation.
               invoke backgroundWorker1::CancelAsync
               set btnCancel::Enabled to false
           end-if

       end method.

       end class.
Labels (4)
Attachments

DISCLAIMER:

Some content on Community Tips & Information pages is not officially supported by Micro Focus. Please refer to our Terms of Use for more detail.
Top Contributors
Version history
Revision #:
1 of 1
Last update:
‎2019-08-15 18:43
Updated by:
 
The opinions expressed above are the personal opinions of the authors, not of Micro Focus. By using this site, you accept the Terms of Use and Rules of Participation. Certain versions of content ("Material") accessible here may contain branding from Hewlett-Packard Company (now HP Inc.) and Hewlett Packard Enterprise Company. As of September 1, 2017, the Material is now offered by Micro Focus, a separately owned and operated company. Any reference to the HP and Hewlett Packard Enterprise/HPE marks is historical in nature, and the HP and Hewlett Packard Enterprise/HPE marks are the property of their respective owners.