Using BackgroundWorker
is the simplest way to do what you're trying to do. BackgroundWorker
simplifies the logic of dealing with threads, leaving you with very little code you have to write. You just have to handle three events (DoWork
, ProgressChanged
, and RunWorkerCompleted
) and follow a few principles:
- Don't ever update the UI inside your long-running method. Have it call
ReportProgress
instead and handle the ProgressChanged
event in the UI logic.
- Understand that since the worker isn't running on the UI thread, an exception that your method throws doesn't automatically show up in the UI. It just gets silently written to the console. It's very important to check the
Error
property of the RunWorkerCompletedEventArgs
when the method is done and handle (or throw) the exception. If you don't do this, you won't know that your method failed.
- If the method can be cancelled, make sure that it periodically checks the
CancellationPending
property to see if cancellation has been requested. If it has, once it's done handling the cancellation, set the Cancel
property on the DoWorkEventArgs
object. Be aware that it's possible for CancellationPending
to be true and Cancel
to be false; this happens, for instance, when the user requests cancellation and the method finishes before it has a chance to check CancellationPending
.
- Correspondingly, check
Cancel
in your RunWorkerCompleted
event handler, so that your UI can provide the proper response to what happened while the worker was running.
The examples in the documentation all show the DoWork
event handler calling a method of the form. This is almost certainly not what you want to do. Separating business logic from UI is a good idea in general; in background tasks it's essential. If your long-running method is a member of a class that doesn't know that the UI even exists, there's no danger that you'll inadvertently have it call a method that updates a status bar or something.