BackgroundWorker取消 [英] BackgroundWorker cancellation
问题描述
我在winforms应用程序中使用BackgroundWorker来执行另一个类中发生的长时间运行的任务(执行数据库操作).由于所有工作都是在另一个类中完成的,因此取消并不是那么简单.我在另一个类(GenerateStats
)中使用一个事件在后台操作完成时更新进度.我想通过取消操作来做类似的事情.我不能只在DoWork函数中调用cancellationPending
,因为该方法要等到它完成并且无法达到目的时才能看到它.我想要取消功能,而不必将BackgroundWorker传递给generateForSubject()
.无论如何,这是否可以支持从GenerateStats
类中的generateForSubject()
方法取消.这是操作在其中执行的类的实例:
I am using a BackgroundWorker in my winforms app to perform a long running task that occurs in another class (performing database operations). Since all the work is done in another class the cancellation is not as simple. I am using an event in the other class (GenerateStats
) to update the progress as the background operation completes. I want to do a similar thing with cancelling the operation. I can't just call cancellationPending
in the DoWork function because the method would never see it until it finishes and that defeats the purpose. I want the cancellation functionality without having the pass the BackgroundWorker to generateForSubject()
. Is there anyway that this can support cancellation from the generateForSubject()
method in GenerateStats
class. This is the instantiation of the class that the operation performs in:
GenerateStats genStats = new GenerateStats();
这是我的DoWork函数,每当调用另一个类中的事件时,该函数就会调用ReportProgress
方法.它还从另一个执行操作的类generateForSubject()
中调用该方法.
This is my DoWork function, which calls the ReportProgress
method anytime the event in the other class gets called. It also calls the method from the other class generateForSubject()
that performs the operations.
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()
This is the button click event handler that should initiate the cancellation and run CancelAsync()
private void btnStop_Click(object sender, EventArgs e)
{
if (backgroundWorker.IsBusy)
{
backgroundWorker.CancelAsync();
}
}
这是我执行操作的单独类,同时创建ProgressChanged事件处理程序,因此我的类可以使用进度信息更新表单.如果取消的执行方式相似,那就太棒了.
This is my separate class that performs the operation, along with creating the ProgressChanged event handler so my class can updated the form with info on progress. It would be awesome if cancellation can perform similarly.
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
Just to clarify if there is any uncertainty as to what I am asking, is there any way for me to support cancellation of my backgroundWorker in the other class without passing the backgroundWorker to the method. If there is absolutely no way and I have to, then I will pass the backgroundWorker
推荐答案
如果您更具体地表示不愿意通过BackgroundWorker
实例,这将对您有所帮助.知道为什么这是设计要求,可以帮助您更好地回答问题.
It would be helpful if you could be more specific about your reluctance to pass the BackgroundWorker
instance. Knowing why that's a design requirement could help produce a better answer to your question.
也就是说,您可以应用与ProgressChanged
事件相同的理念,也可以委派取消检查.例如:
That said, you can apply the same philosophy you did for the ProgressChanged
event and delegate the cancellation check as well. For example:
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
报告进度而无需直接访问
This allows the GenerateStats
class to check for pending cancellation without having direct access to the BackgroundWorker
instance, just as the ProgressChanged
event allows it to report progress via the BackgroundWorker
without direct access to the BackgroundWorker
.
这篇关于BackgroundWorker取消的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!