I would like to use the BackgroundWorker to perform a database transaction from a GUI.
How can I command the BackgroundWorker to perform the work and then WAIT for the worker to complete while keeping the GUI responsive?
Do I have to use DoEvents for this purpose, or is there another way?
Asking “How can I command the
BackgroundWorkerto perform the work and then WAIT for the worker to complete while keeping the GUI responsive?” is really asking “How do I use theBackgroundWorker?”. That’s whatBackgroundWorkerdoes.When you write a background task, you’re basically breaking up a method into four pieces:
So you’re going to need to write four methods. The first is a method that creates a
BackgroundWorker, adds event handlers to itsDoWork,ProgressChanged, andRunWorkerCompletedevents, puts the UI into whatever state it needs to be in while the task is running, and callsRunWorkerAsyncto start the task.The other three are those three event handlers.
DoWorkis aDoWorkEventHandlerthat does the work, and that callsReportProgresswhenever it needs to report its progress to the UI.ProgressChangedis aProgressChangedEventHandlerthat actually updates the UI whenReportProgressgets called. AndRunWorkerCompletedis aRunWorkerCompletedEventHandlerthat tells the UI that the job is done.That’s all there is to it.
Well, not quite all. First, you have to make sure that you check and handle the
Errorproperty in your completion handler. If you don’t do this, you will have no way of knowing that your do-work method threw an exception, since it’s not happening in the UI thread and thus doesn’t throw an exception that you can see. (It’ll show up in the Output window, if you’re looking for it.)Second, you have to make sure that the
DoWorkEventHandlerdoesn’t touch anything in the UI. This can be tricky if you’re using the MVVM pattern and you haven’t planned for this contingency, because through the magic of data binding you probably have things in your model that update the views that the UI is bound to, which means that manipulating the model in your do-work method is manipulating the UI. Assuming that you’re implementingINotifyPropertyChanged, a good way to avoid trouble here is to build a mechanism whereby your views don’t raisePropertyChangedevents while a background task is running.You also need to figure out what pieces of the UI should be disabled while the task is running. This depends on your UI. The answer might be “all of it,” and it might not. One of the things that makes using a modal form for your progress indicator attractive is that it frees you up from having to figure this out, since your entire UI is disabled while the modal form is open. If you’re disabling controls or turning off property-change notifications in the launch method, you’ll need to turn things back on again in the completion method.
And remember: any updates that the active parts of your UI make to your data model are a potential source of cross-thread data access errors. If your UI and the background thread ever update the same object, bad things happen – they’re particularly bad if you haven’t handled the
Errorproperty in your completion handler, and the cross-thread exception kills the background task without your knowing it. If it sounds like I’m dwelling on this, it’s because I’ve lost a lot of hours of my life to doing this particular thing wrong.