2012-05-07 4 views
5

Mam pracę w tle, która uruchamia pojedynczy proces. Chcę móc anulować przetwarzanie w trakcie jego działania, ale kiedy zadzwonię do metody CancelAsync(), nigdy tak naprawdę nie anuluje. Gdzie się mylę?Backgroundworker.CancelAsync() nie działa

Oto() metoda DoWork:

 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; 
      } 
     } 
    } 

Oto metoda, która rozpoczyna przetwarzanie:

 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"; 
    } 

A oto WorkerCompleted() wydarzenie:

 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

Masz tylko bardzo małe okienko, które sprawdza anulowanie. Nie upuścisz go. –

+1

OT ale w Twoim Ukończonym treserze czek na e.Error powinien iść pierwszy. –

Odpowiedz

5

Tak naprawdę nie ma sposobu, aby anulować operację. Problem polega na tym, że ten kod nie ma żadnego sposobu na przerwanie po uruchomieniu tego kodu. Tak więc, co się dzieje, to że anulujesz, ale anulowanie nigdy nie zostanie zarejestrowane, chyba że anulujesz, zanim rozpocznie się akcja. Po zakończeniu tej czynności metoda DoWork powraca pomyślnie, a pracownik tła nigdy nie uruchamia anulowania.

EDIT: Jeśli masz sposób na przełamanie tekstu na mniejsze kawałki, które mogą być następnie „przeszukiwane i zastąpione”, można pętlę przez te segmenty i przeprowadzić kontrolę rezygnacji z każdej pętli. Musisz się jednak upewnić, że łańcuch wyszukiwania znajduje się pomiędzy tymi granicami przerwań, więc może to potrwać dłużej, aby umożliwić anulowanie.

+0

tego się obawiałem. Mój proces "tła" jest jednym długim procesem, więc nie byłem pewien, jak zabić ten pojedynczy proces. Czy istnieje sposób, aby to zrobić? – ganders

+3

Ponieważ twoja metoda DoWork po prostu uruchamia pojedyncze polecenie, to nie, nie ma sposobu na anulowanie tego polecenia. Możesz tylko sprawdzić anulowanie między poleceniami (szczególnie jeśli robisz pętlę). Możesz, być może, podzielić tekst na mniejsze segmenty, a następnie przepuścić pętlę 'FindReplace', sprawdzając anulowanie w każdej pętli. – saluce

+0

Wygląda na to, że nie powinienem używać pracy w tle, ale użyć tylko osobnego wątku (może wywoływanego z pracy w tle, aby nadal zgłaszać postępy?). Następnie, po kliknięciu Anuluj, mogę zadzwonić do wątku.Abort (), czy coś takiego? Czy to "inteligentne" zrobić? – ganders

7

CancelAsync w rzeczywistości nie przerwie twojej nici ani nic coś takiego jak to. Wysyła ona wiadomość do wątku roboczego, która powinna być anulowana za pomocą funkcji za pośrednictwem funkcji BackgroundWorker.CancellationPending. Twój delegat DoWork , który jest uruchamiany w tle, musi okresowo sprawdzać tę właściwość i obsługiwać samą anulację.

Czytaj więcej here

3

Twój kod ma rację, ale jeśli przeczytasz go jeszcze raz, zobaczysz, że po uruchomieniu pracownika w tle, wkrótce wykracza poza kontrolę anulowania. Później, nawet jeśli spróbujesz anulować, nie będzie już działać.

Musisz przeprojektować wyszukiwanie i zamienić algorytm, aby zawierał również test anulowania, aby umożliwić anulowanie zgodnie z oczekiwaniami.