So I have a webpage scraper that uses backgroundworker to process each page. I also want to mention that I’m using MVVM light framework.
Inside my MainViewModel Constructor I am initializing the backgroundworker:
backgroundWorker = new BackgroundWorker()
{
WorkerReportsProgress = true,
WorkerSupportsCancellation = true
};
backgroundWorker.DoWork += new DoWorkEventHandler(backgroundWorker_DoWork);
On the LoadCompleted event of a WebBrowser control I start the backgroundworker:
wb = sender; //sender is the webbrowser control
if (!backgroundWorker.IsBusy)
{
backgroundWorker.RunWorkerAsync();
}
My next two methods are DoWork And 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();
}
The fetchpage method will grab the sourcecode of the webbrowser control and start parsing it for content.
Inside of FetchPage I’m using BeginInvoke to update my UI thread:
Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(
() =>
{ ... }
My issue:
When I hit the Cancel button the StopWork method get’s invoked, the cancel property on the backgroundWorker is set correctly to true, but the app just keeps going on. My if (wk.CancellationPending) is always false.
Any idea on what am I doing wrong here? I looked at tons of examples online and here on StackOverflow and they all state the same things that i already done.
Thanks.
EDIT:
After Ernos reply I tried passing the CancellationPending property to the FetchPage method and check for it in different locations, but it did not stop the processing.
void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker wk = sender as BackgroundWorker;
if (wb != null)
{
FetchPage(wb, wk.CancellationPending);
_resetEvent.Set();
}
}
Inside of FetchPage I’m using BeginInvoke to update my UI thread:
private void FetchPage(object sender, bool stopAll)
{
if (stopAll)
{
return;
}
Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(
() =>
{ ... }
What I have tried and worked was:
private bool stopAllWork = false;
...
private void StopWork(object sender)
{
stopAllWork = true;
backgroundWorker.CancelAsync();
_resetEvent.WaitOne();
}
and then inside DoWork:
void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker wk = sender as BackgroundWorker;
if (wb != null)
{
FetchPage(wb, stopAllWork);
_resetEvent.Set();
}
}
Now, because of this implementation my concern is if there will be any rogue backgroundWorkers remaining?
You need to evaluate the
CancellationPendinginside theFetchPagemethod.You are checking it AFTER the load of work.