问题
Users of my application type HTML into a TextBox control.
I want my application to validate their input in the background.
Because I don't want to hammer the validation service, I've tried to build in a one-second delay before each validation.
However, I don't seem to be able to correctly interrupt an already-running BackgroundWorker process.
My Visual Basic code:
Sub W3CValidate(ByVal WholeDocumentText As String)
'stop any already-running validation
If ValidationWorker.IsBusy Then
ValidationWorker.CancelAsync()
'wait for it to become ready
While ValidationWorker.IsBusy
'pause for one-hundredth of a second
System.Threading.Thread.Sleep(New TimeSpan(0, 0, 0, 0, 10))
End While
End If
'start validation
Dim ValidationArgument As W3CValidator = New W3CValidator(WholeDocumentText)
ValidationWorker.RunWorkerAsync(ValidationArgument)
End Sub
It seems that after calling my BackgroundWorker's CancelAsync(), its IsBusy never becomes False. It gets stuck in an infinite loop.
What am I doing wrong?
回答1:
Try something like this:
bool restartWorker = false;
void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// add other code here
if (e.Cancelled && restartWorker)
{
restartWorker = false;
backgroundWorker1.RunWorkerAsync();
}
}
private void button1_Click(object sender, EventArgs e)
{
if (backgroundWorker1.IsBusy)
{
restartWorker = true;
backgroundWorker1.CancelAsync();
}
else
backgroundWorker1.RunWorkerAsync();
}
回答2:
In your background worker process loop you need to check for backgroundWorkerPageProcess.CancellationPending
and exit accordingly. Then once it exists your while loop isBusy should be flagged accordingly.
Update: After you set Cancel = true are you returning out of the method? spitballing here Update 2: You have the WorkerSupportsCancellation flag set to true on the backgroundworker? Also in worker completed method return out if e.Cancelled.... more spitballs
Update 3: after some checking and compilation of my own it appears the damn thing never gets out of isbusy within the same method. -One option is to disable the button while busy and have another to cancel, only for the user to reclick the validation. -Or on your worker completed method if(e.Cancelled) call your validation method with appropriate text....
either way is kind of bust though. Sorry to not be of much help here.
回答3:
I found the answer in this article:
BackgroundWorker Closure and Overridable Task by Patrick Smacchia
I've adapted his code:
Private _ValidationArgument As W3CValidator
Sub W3CValidate(ByVal WholeDocumentText As String)
If _ValidationArgument IsNot Nothing Then
_ValidationArgument = New W3CValidator(WholeDocumentText)
Exit Sub
End If
If Not ValidationWorker.IsBusy Then
ValidationWorker.RunWorkerAsync(New W3CValidator(WholeDocumentText))
Exit Sub
End If
_ValidationArgument = New W3CValidator(WholeDocumentText)
ValidationWorker.CancelAsync()
Dim TimerRetryUntilWorkerNotBusy As New Windows.Threading.DispatcherTimer
AddHandler TimerRetryUntilWorkerNotBusy.Tick, AddressOf WorkTicker
TimerRetryUntilWorkerNotBusy.Interval = New TimeSpan(1) '100 nanoseconds
TimerRetryUntilWorkerNotBusy.Start()
End Sub
Sub WorkTicker(ByVal sender As Object, ByVal e As System.EventArgs)
If ValidationWorker.IsBusy Then
Exit Sub
End If
DirectCast(sender, Windows.Threading.DispatcherTimer).Stop()
ValidationWorker.RunWorkerAsync(_ValidationArgument)
_ValidationArgument = Nothing
End Sub
来源:https://stackoverflow.com/questions/635152/how-do-i-properly-cancel-and-restart-a-backgroundworker-process