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

1 Likes
over 2 years ago

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.

Tags:

Labels:

Visual Studio
Forms
BackgroundWorker
Windows
Comment List
Anonymous
Related Discussions
Recommended