BackgroundWorker取消

我在winforms应用程序中使用BackgroundWorker来执行在另一个类中执行的长时间运行的任务(执行数据库操作)。 由于所有工作都在另一个class级完成,因此取消并不那么简单。 我在另一个类( GenerateStats )中使用一个事件来在后台操作完成时更新进度。 我想取消操作做类似的事情。 我不能只在DoWork函数中调用cancellationPending ,因为该方法在完成之前永远不会看到它并且会破坏目的。 我希望取消function,而无需将BackgroundWorker传递给generateForSubject() 。 无论如何,这可以支持从GenerateStats类中的generateForSubject()方法取消。 这是操作执行的类的实例化:

 GenerateStats genStats = new GenerateStats(); 

这是我的DoWork函数,它可以在调用其他类中的事件时调用ReportProgress方法。 它还从执行操作的其他类generateForSubject()调用该方法。

 private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e) { BackgroundWorker worker = sender as BackgroundWorker; genStats.ProgressChanged += (s, pe) => worker.ReportProgress(pe.ProgressPercentage, pe.UserState); genStats.generateForSubject(); } 

这是应该启动取消并运行CancelAsync()的按钮单击事件处理程序

 private void btnStop_Click(object sender, EventArgs e) { if (backgroundWorker.IsBusy) { backgroundWorker.CancelAsync(); } } 

这是我执行操作的单独类,以及创建ProgressChanged事件处理程序,因此我的类可以使用有关进度的信息更新表单。 如果取消可以类似地执行,那将是很棒的。

 public event ProgressChangedEventHandler ProgressChanged; protected virtual void OnProgressChanged(int progress, string message) { if (ProgressChanged != null) { ProgressChanged(this, new ProgressChangedEventArgs(progress, message)); } } public void generateForSubject() { //Perform db operation not important, but it takes time OnProgressChanged(33, "Finished 1st set of stats"); //I hope to check for cancellation here //Perform db operation not important, but it takes time OnProgressChanged(66, "Finished 2nd set of stats"); //I hope to check for cancellation here //Perform db operation not important, but it takes time OnProgressChanged(99, "Finished 3rd set of stats"); //I hope to check for cancellation here } 

只是为了澄清我的问题是否存在任何不确定性,是否有任何方法可以支持在其他类中取消我的backgroundWorker而不将backgroundWorker传递给该方法。 如果完全没有办法,我必须,然后我将通过backgroundWorker

如果您可以更具体地了解您不愿意传递BackgroundWorker实例,那将会很有帮助。 了解为什么这是一个设计要求可以帮助您更好地回答您的问题。

也就是说,您可以应用与ProgressChanged事件相同的理念,并委派取消检查。 例如:

 class GenerateStats { public event EventHandler CheckCancel; private bool OnCheckCancel() { EventHandler handler = CheckCancel; if (handler != null) { CancelEventArgs e = new CancelEventArgs(); handler(this, e); return e.Cancel; } return false; } public void generateForSubject() { //Perform db operation not important, but it takes time OnProgressChanged(33, "Finished 1st set of stats"); if (OnCheckCancel()) { // Or other cancellation logic here return; } //Perform db operation not important, but it takes time OnProgressChanged(66, "Finished 2nd set of stats"); if (OnCheckCancel()) { // Or other cancellation logic here return; } //Perform db operation not important, but it takes time OnProgressChanged(99, "Finished 3rd set of stats"); if (OnCheckCancel()) { // Or other cancellation logic here return; } } } private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e) { BackgroundWorker worker = sender as BackgroundWorker; genStats.ProgressChanged += (s, pe) => worker.ReportProgress(pe.ProgressPercentage, pe.UserState); genStats.CheckCancel += (sender1, e1) => e1.Cancel = worker.CancellationPending; genStats.generateForSubject(); } 

这允许GenerateStats类在不直接访问BackgroundWorker实例的情况下检查挂起的取消,就像ProgressChanged事件允许它通过BackgroundWorker报告进度而无需直接访问BackgroundWorker

您应该定期检查CancellationPending属性以查看是否已取消请求。 然后决定取消操作。 请参阅MSDN链接 。

来自MSDN:

请注意,DoWork事件处理程序中的代码可能会在发出取消请求时完成其工作,并且您的轮询循环可能会将CancellationPending设置为true。 在这种情况下,即使发出取消请求,RunWorkerCompleted事件处理程序中System.ComponentModel.RunWorkerCompletedEventArgs的Canceled标志也不会设置为true。 这种情况称为竞争条件,是multithreading编程中的常见问题。 有关multithreading设计问题的更多信息,请参阅托管线程最佳实践。

编辑:

如果您不希望将backgroundworker传递给generateForSubject方法。 收到CancelAsync时,在类中设置属性。 并在每次操作之前从generateForSubject方法检查此属性的值。