如何正确停止BackgroundWorker

Stu*_*ens 60 .net c# backgroundworker winforms


我有一个有2个组合框的表格.我想combobox2.DataSource基于combobox1.Text和填充combobox2.Text(我假设用户已完成输入combobox1并且正在输入中combobox2).所以我有一个这样的事件处理程序combobox2:

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 );
}
Run Code Online (Sandbox Code Playgroud)

至于构建DataSource是一个耗时的过程(它创建一个对数据库的请求并执行它)我决定使用BackgroundWorker在另一个进程中执行它更好.因此,当cmbDataSourceExtractor尚未完成其工作并且用户再键入一个符号时,会出现这种情况.在这种情况下,我在这一行上得到一个例外,
cmbDataSourceExtractor.RunWorkerAsync(filledComboboxValues );说明BackgroundWorker正忙,无法同时执行多个操作.
如何摆脱这种异常?
提前致谢!

Hac*_*ese 91

CancelAsync实际上并没有中止你的线程或类似的东西.它向工作线程发送一条消息,告知应该取消工作BackgroundWorker.CancellationPending.您在后台运行的DoWork委托必须定期检查此属性并自行处理取消.

棘手的部分是您的DoWork委托可能是阻塞的,这意味着您在DataSource上所做的工作必须先完成,然后才能执行其他操作(例如检查CancellationPending).您可能需要将您的实际工作移动到另一个异步委托(或者更好的是,将工作提交给ThreadPool),并让您的主工作线程轮询,直到此内部工作线程触发等待状态,或者它检测到CancellationPending.

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

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


jen*_*ild 30

如果你在CancelAsync()和RunWorkerAsync()之间添加一个循环,这样就可以解决你的问题

 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 );
  }
Run Code Online (Sandbox Code Playgroud)

调用Application.DoEvents()的while循环将导致新工作线程的执行,直到当前的线程正确取消,请记住,您仍然需要处理工作线程的取消.有类似的东西:

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

第一个代码片段中的Application.DoEvents()将继续处理您的GUI线程消息队列,因此仍然会处理取消和更新cmbDataSourceExtractor.IsBusy属性的偶数(如果您只是添加了一个continue而不是Application.DoEvents()循环会将GUI线程锁定为忙状态,并且不会处理事件以更新cmbDataSourceExtractor.IsBusy)


Dan*_*ger 6

您必须使用主线程和BackgroundWorker之间共享的标志,例如BackgroundWorker.CancellationPending.如果希望BackgroundWorker退出,只需使用BackgroundWorker.CancelAsync()设置标志.

MSDN有一个示例:http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.cancellationpending.aspx