我在我的winforms应用程序中使用一个BackgroundWorker来执行另一个类中发生的长时间运行的任务(执行数据库操作)。因为所有的工作都是在另一个类中完成的,所以取消就不那么简单了。当后台操作完成时,我使用另一个类中的一个事件(GenerateStats)来更新进度。我也想做一件类似的事情,取消手术。我不能只在cancellationPending函数中调用DoWork,因为方法在它完成之前永远不会看到它,这就违背了它的目的。我想要取消功能,而不需要将BackgroundWorker传递给generateForSubject()。这是否可以支持从generateForSubject()方法取消GenerateStats类。这是操作在其中执行的类的实例化:
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
发布于 2014-11-24 05:25:58
如果您能够更具体地说明不愿意传递BackgroundWorker实例,这将是有帮助的。了解为什么这是一个设计要求,可以帮助您更好地回答您的问题。
也就是说,您可以应用与ProgressChanged事件相同的理念,也可以委托取消检查。例如:
class GenerateStats
{
public event EventHandler<CancelEventArgs> CheckCancel;
private bool OnCheckCancel()
{
EventHandler<CancelEventArgs> 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一样。
发布于 2014-11-24 04:58:22
您的方法应该定期检查CancellationPending属性,以确定是否提出了取消请求。然后决定取消手术。有关此问题,请参见MSDN链路。
来自MSDN:
请注意,DoWork事件处理程序中的代码可能会在发出取消请求时完成其工作,并且轮询循环可能会错过将CancellationPending设置为true。在这种情况下,即使发出了取消请求,RunWorkerCompleted事件处理程序中的已取消标志也不会设置为true。这种情况称为争用条件,是多线程编程中常见的问题。有关多线程设计问题的详细信息,请参阅托管线程最佳实践。
编辑:
如果不希望将背景工作者传递给generateForSubject方法。当收到CancelAsync时,在类中设置一个属性。并在每次操作之前从generateForSubject方法中检查此属性的值。
https://stackoverflow.com/questions/27097968
复制相似问题