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.