所以我有一个网页抓取工具,它使用backgroundworker来处理每个页面。我还想提一下,我正在使用MVVM轻型框架。
在我的MainViewModel构造函数中我正在初始化backgroundworker:
backgroundWorker = new BackgroundWorker()
{
WorkerReportsProgress = true,
WorkerSupportsCancellation = true
};
backgroundWorker.DoWork += new DoWorkEventHandler(backgroundWorker_DoWork);
在WebBrowser控件的LoadCompleted事件上,我启动了后台工作程序:
wb = sender; //sender is the webbrowser control
if (!backgroundWorker.IsBusy)
{
backgroundWorker.RunWorkerAsync();
}
接下来的两种方法是DoWork和StopWork:
private System.Threading.AutoResetEvent _resetEvent = new System.Threading.AutoResetEvent(false);
private object wb;
void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker wk = sender as BackgroundWorker;
if (wb != null)
{
FetchPage(wb);
if (wk.CancellationPending)
{
MessageBox.Show("Cancellation pending!");
}
_resetEvent.Set();
}
}
private void StopWork(object sender)
{
backgroundWorker.CancelAsync();
_resetEvent.WaitOne();
}
fetchpage方法将获取webbrowser控件的源代码并开始解析它以获取内容。
在FetchPage内部我使用BeginInvoke来更新我的UI线程:
Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(
() =>
{ ... }
我的问题: 当我点击取消按钮调用StopWork方法时,backgroundWorker上的cancel属性被正确设置为true,但应用程序只是继续进行。我的if(wk.CancellationPending)总是假的。
我在这里做错了什么?我在线查看了大量的示例,并在StackOverflow上进行了查看,他们都说明了我已经完成的相同事情。
感谢。
编辑:
在Ernos回复后,我尝试将CancellationPending属性传递给FetchPage方法并在不同位置检查它,但它没有停止处理。
void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker wk = sender as BackgroundWorker;
if (wb != null)
{
FetchPage(wb, wk.CancellationPending);
_resetEvent.Set();
}
}
在FetchPage内部我使用BeginInvoke来更新我的UI线程:
private void FetchPage(object sender, bool stopAll)
{
if (stopAll)
{
return;
}
Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(
() =>
{ ... }
我尝试过的工作是:
private bool stopAllWork = false;
...
private void StopWork(object sender)
{
stopAllWork = true;
backgroundWorker.CancelAsync();
_resetEvent.WaitOne();
}
然后在DoWork内部:
void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker wk = sender as BackgroundWorker;
if (wb != null)
{
FetchPage(wb, stopAllWork);
_resetEvent.Set();
}
}
现在,由于这个实现,我担心的是,是否还会有任何流氓背景工作者?
答案 0 :(得分:2)
您需要评估CancellationPending
方法中的FetchPage
。
你正在检查工作量。
答案 1 :(得分:1)
Erno是对的。在完成所有工作后,您正在检查它是否被取消。为了保持模块化,您可以考虑不将后台工作程序传递给FetchPage;相反,如果您要取消,则传递一个返回的函数。
public void FetchPage(WebBrowser wb, Func<bool> cancelNow)
{
...
if(cancelNow()) {
return;
}
...
}
你会这样称呼它
FetchPage(wb, () => wk.CancellationPending);
但您可以将该函数放在另一个不使用后台工作程序的应用程序中,并像这样调用它:
FetchPage(wb, () => false);
注意:请确保在工作完成时检查是否应取消。例如,如果大多数工作发生在循环中,请检查循环内部。如果有一系列步骤,请检查每个步骤。