Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to stop BackgroundWorker correctly


I have a form with 2 comboboxes on it. And I want to fill combobox2.DataSource based on combobox1.Text and combobox2.Text (I assume that the user has completed input in combobox1 and is in the middle of inputting in combobox2). So I have an event handler for combobox2 like this:

private void combobox2_TextChanged(object sender, EventArgs e) {     if (cmbDataSourceExtractor.IsBusy)        cmbDataSourceExtractor.CancelAsync();      var filledComboboxValues = new FilledComboboxValues{ V1 = combobox1.Text,        V2 = combobox2.Text};     cmbDataSourceExtractor.RunWorkerAsync(filledComboboxValues ); } 

As far as building DataSource is time-consuming process (it creates a request to database and executes it) I decided that it's better to perform it in another process using BackgroundWorker. So there's a scenario when cmbDataSourceExtractor hasn't completed its work and the user types one more symbol. In this case I get an exception on this line
cmbDataSourceExtractor.RunWorkerAsync(filledComboboxValues ); about that BackgroundWorker is busy and cannot perform several actions in the same time.
How to get rid of this exception?
Thanks in advance!

like image 544
StuffHappens Avatar asked Jan 19 '11 07:01

StuffHappens


People also ask

How do I stop BackgroundWorker?

BackgroundWorker has its own, unique way of doing cancellation. First, when constructing the BGW instance, be sure to set BackgroundWorker. WorkerSupportsCancellation to true . Then, the calling code can request the worker to cancel by calling BackgroundWorker.

What is the difference between BackgroundWorker and thread?

BackgroundWorker has already implemented functionality of reporting progress, completion and cancellation - so you don't need to implement it by yourself. Usage of Thread gives you more control over the async process execution (e.g. thread priority or choosing beetween foreground/background thread type).

How do I use BackgroundWorker?

The steps are extremely simple: Create a BackgroundWorker object. Tell the BackgroundWorker object what task to run on the background thread (the DoWork function). Tell it what function to run on the UI thread when the work is complete (the RunWorkerCompleted function).

What is BackgroundWorker in Winforms?

The BackgroundWorker class exposes the DoWork event, to which your worker thread is attached through a DoWork event handler. The DoWork event handler takes a DoWorkEventArgs parameter, which has an Argument property.


2 Answers

CancelAsync doesn't actually abort your thread or anything like that. It sends a message to the worker thread that work should be cancelled via BackgroundWorker.CancellationPending. Your DoWork delegate that is being run in the background must periodically check this property and handle the cancellation itself.

The tricky part is that your DoWork delegate is probably blocking, meaning that the work you do on your DataSource must complete before you can do anything else (like check for CancellationPending). You may need to move your actual work to yet another async delegate (or maybe better yet, submit the work to the ThreadPool), and have your main worker thread poll until this inner worker thread triggers a wait state, OR it detects CancellationPending.

http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.cancelasync.aspx

http://www.codeproject.com/KB/cpp/BackgroundWorker_Threads.aspx

like image 104
moribvndvs Avatar answered Sep 23 '22 22:09

moribvndvs


If you add a loop between the CancelAsync() and the RunWorkerAsync() like so it will solve your problem

 private void combobox2_TextChanged(object sender, EventArgs e)  {      if (cmbDataSourceExtractor.IsBusy)         cmbDataSourceExtractor.CancelAsync();       while(cmbDataSourceExtractor.IsBusy)         Application.DoEvents();       var filledComboboxValues = new FilledComboboxValues{ V1 = combobox1.Text,         V2 = combobox2.Text};      cmbDataSourceExtractor.RunWorkerAsync(filledComboboxValues );   } 

The while loop with the call to Application.DoEvents() will hault the execution of your new worker thread until the current one has properly cancelled, keep in mind you still need to handle the cancellation of your worker thread. With something like:

 private void cmbDataSourceExtractor_DoWork(object sender, DoWorkEventArgs e)  {       if (this.cmbDataSourceExtractor.CancellationPending)       {           e.Cancel = true;           return;       }       // do stuff...  } 

The Application.DoEvents() in the first code snippet will continue to process your GUI threads message queue so the even to cancel and update the cmbDataSourceExtractor.IsBusy property will still be processed (if you simply added a continue instead of Application.DoEvents() the loop would lock the GUI thread into a busy state and would not process the event to update the cmbDataSourceExtractor.IsBusy)

like image 29
jenovachild Avatar answered Sep 20 '22 22:09

jenovachild