2012-05-07 7 views
5

Ich habe einen Hintergrundarbeiter, der einen einzelnen Prozess ausführt. Ich möchte die Verarbeitung abbrechen können, während sie läuft, aber wenn ich die CancelAsync() -Methode aufruft, wird sie nie abgebrochen. Wo liege ich falsch?Backgroundworker.CancelAsync() funktioniert nicht

Hier ist der DoWork() -Methode:

 private void bgw_DoWork(object sender, DoWorkEventArgs e) 
    { 
     BackgroundWorker b = sender as BackgroundWorker; 

     if (b != null) 
     { 
      if (!b.CancellationPending) 
      { 
       try 
       { 
        // Let's run the process as a backgroundworker so we have the ability to cancel the search, and/or be able to view results while it's still searching 
        ProcessParameters pp = e.Argument as ProcessParameters; 

        if (pp.DoReplace) 
         results = FindReplace.FindReplace.FindAndReplace(pp.PathToSearch, pp.FindText, pp.ReplaceText, pp.UseRegularExpressions, pp.IncludeList, pp.ExcludeList, pp.RecurseSubdirectories, pp.IgnoreCase); 
        else 
         results = FindReplace.FindReplace.Find(pp.PathToSearch, pp.FindText, pp.UseRegularExpressions, pp.IncludeList, pp.ExcludeList, pp.RecurseSubdirectories, pp.IgnoreCase); 
       } 
       catch (Exception ex) 
       { 
        MessageBox.Show(ex.ToString()); 
       } 
      } 
      else 
      { 
       // Cancel was clicked 
       e.Cancel = true; 
      } 
     } 
    } 

Hier ist die Methode, die die Verarbeitung beginnt:

 private void btnGo_Click(object sender, EventArgs e) 
    { 
     if (btnGo.Text == "Cancel") 
     { 
      if (DialogResult.Yes == MessageBox.Show("Are you sure you wish to cancel?", "Cancel Requested", MessageBoxButtons.YesNo, MessageBoxIcon.Question)) 
       bgw.CancelAsync(); 

      return; 
     } 

     if (tbFind.Text.Length == 0) 
     { 
      MessageBox.Show("Find text is not valid."); 
      return; 
     } 

     tbFound.Text = String.Empty; 
     tbFoundInThisFile.Text = String.Empty; 
     lvResults.Items.Clear(); 
     includeList = null; 
     excludeList = null; 
     results = null; 

     if (radDirectory.Checked && !radFile.Checked) 
     { 
      includeList = BuildIncludeExcludeList(tbIncludeFiles.Text); 
      excludeList = BuildIncludeExcludeList(tbExcludeFiles.Text); 
     } 

     ProcessParameters pp = null; 

     if (chkReplace.Checked) 
      pp = new ProcessParameters(tbPath.Text, tbFind.Text, tbReplace.Text, chkUseRegEx.Checked, includeList, excludeList, chkRecursion.Checked, chkIgnoreCase.Checked, true); 
     else 
      pp = new ProcessParameters(tbPath.Text, tbFind.Text, chkUseRegEx.Checked, includeList, excludeList, chkRecursion.Checked, chkIgnoreCase.Checked, false); 

     bgw.RunWorkerAsync(pp); 

     // Toggle fields to locked while it's running 
     btnGo.Text = "Cancel"; 
    } 

Und hier ist der WorkerCompleted() Ereignis:

 private void bgw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
    { 
     btnGo.Text = "Go"; 

     string message = String.Empty; 
     const string caption = "FindAndReplace is Complete"; 

     if (!e.Cancelled) 
     { 
      if (results != null) 
      { 
       tbFound.Text = results.Found.ToString(); 
       tbSearched.Text = results.FilesSearched.ToString(); 
       tbSkipped.Text = results.FilesSkipped.ToString(); 

       message = String.Format("Search finished resulting in {0} match(es).", results.Found); 
      } 
      else 
       message = "The FindAndReplace results were empty. The process was cancelled or there was an error during operation."; 
     } 
     else 
      message = "The FindAndReplace process was cancelled."; 

     if (e.Error != null) 
      message += String.Format("{0}{0}There was an error during processing: {1}", Environment.NewLine, e.Error); 

     MessageBox.Show(message, caption); 
    } 
+1

Sie haben nur ein sehr kleines Fenster, das auf CancellationPending prüft. Du wirst es nicht heiß machen. –

+1

OT aber in Ihrem Completed Handler sollte der Check für e.Error zuerst gehen. –

Antwort

5

Sie haben nicht wirklich eine Möglichkeit, den Vorgang abzubrechen. Das Problem ist, dass dieser Code

hat keine Möglichkeit zu brechen, sobald es beginnt zu laufen. Also, was passiert, ist, dass Sie Abbrechen drücken, aber der Abbruch wird nie registriert, es sei denn, Sie haben abgebrochen, bevor die Aktion beginnt. Sobald diese Aktion abgeschlossen ist, wird die DoWork-Methode erfolgreich zurückgegeben und der Hintergrundarbeiter löst die Löschung nie aus.

BEARBEITEN: Wenn Sie eine Möglichkeit haben, den Text in kleinere Abschnitte zu zerlegen, die dann "gesucht und ersetzt" werden können, können Sie diese Segmente durchlaufen und eine Abbruchprüfung für jede Schleife durchführen. Sie müssen jedoch sicherstellen, dass Sie die Suchzeichenfolge über diese Pausengrenzen hinaus berücksichtigen, sodass LONGER möglicherweise länger dauert, um eine Löschung zuzulassen.

+0

das war, wovor ich Angst hatte. Mein "Hintergrund" -Prozess ist ein langer Prozess, also war ich mir nicht sicher, wie ich diesen einzelnen Prozess beenden könnte. Gibt es überhaupt einen Weg, das zu können? – ganders

+3

Da Ihre DoWork-Methode im Grunde nur einen einzigen Befehl ausführt, dann gibt es keine Möglichkeit, diesen einen Befehl abzubrechen. Sie können nur nach Stornierungen zwischen Befehlen suchen (insbesondere, wenn Sie eine Schleife verwenden). Sie könnten den Text möglicherweise in kleinere Segmente aufteilen, dann den 'FindReplace' durchlaufen und die Löschung für jede Schleife prüfen. – saluce

+0

Also, es klingt wie ich sollte nicht mit einem Hintergrundarbeiter, sondern nur mit einem separaten Thread (vielleicht von der Hintergrundarbeiter aufgerufen, so kann ich noch Fortschritte melden?) Dann, wenn meine Abbrechen geklickt wird, kann ich ein thread.Abort (), oder etwas ähnliches? Ist das "schlau" zu tun? – ganders

7

CancelAsync bricht Ihren Thread oder andere nicht ab Ding wie das. Es sendet eine Nachricht an den Worker-Thread, dass die Arbeit über BackgroundWorker.CancellationPending abgebrochen werden soll. Ihr DoWork Delegat, der im Hintergrund ausgeführt wird, muss die Eigenschaft in regelmäßigen Abständen überprüfen und die Stornierung selbst vornehmen.

mehr here lesen

3

Ihr Code ist richtig, aber wenn Sie ihn noch einmal sorgfältig lesen, werden Sie sehen, dass sobald der Hintergrund-Worker gestartet wird, er bald über die Cancel-Prüfung hinausgeht. Danach, auch wenn Sie versuchen, abzubrechen, wird es nicht mehr funktionieren.

Sie müssen Ihren Such- und Ersetzungsalgorithmus so umgestalten, dass er auch die Abbruchprüfung enthält, um die Löschung wie gewünscht zu unterstützen.