26

Dziś rano grałem z async ctp i mam prosty program z button i label. Kliknij przycisk button, aby rozpocząć aktualizację label, zatrzymując zapisywanie na . Jednak nie jestem pewien, jak zresetować CancellationTokenSource, dzięki czemu mogę ponownie uruchomić proces. Moje kodu jest poniżej:Jak poprawnie zresetować Token Anulowania?

public partial class MainWindow : Window 
{ 
    CancellationTokenSource cts = new CancellationTokenSource(); 
    public MainWindow() 
    { 
     InitializeComponent(); 
     button.Content = "Start"; 
    } 

    async Task DoWork(CancellationToken cancelToken) 
    { 
     int i = 0; 
     while (!cancelToken.IsCancellationRequested) 
     { 
      label.Content = i++.ToString(); 
      await TaskEx.Delay(50, cancelToken); 
     } 
    } 

    private void Button_Click(object sender, RoutedEventArgs e) 
    { 
     if (button.Content == "Start") 
     { 
      button.Content = "Stop"; 
      DoWork(cts.Token); 
     } 
     else 
     { 
      button.Content = "Start"; 
      cts.Cancel(); 
     } 
    } 
} 
+0

Czy to C# 5.0? Nie kompiluje się w .NET 4.0 – Fulproof

+0

nadal można uzyskać ctp na 4.0. Jednak tak, to jest cecha 4.5. – poco

Odpowiedz

51

Trzeba odtworzyć CancellationTokenSource - nie ma sposobu, aby „zresetować” ten jeden raz go ustawić.

To może być tak proste, jak:

private void Button_Click(object sender, RoutedEventArgs e) 
{ 
    if (button.Content == "Start") 
    { 
     button.Content = "Stop"; 
     cts.Dispose(); // Clean up old token source.... 
     cts = new CancellationTokenSource(); // "Reset" the cancellation token source... 
     DoWork(cts.Token); 
    } 
    else 
    { 
     button.Content = "Start"; 
     cts.Cancel(); 
    } 
} 
+1

Kiedy należy pozbyć się jej na końcu aplikacji? Ponieważ musisz poczekać, zanim wątek zostanie ukończony, w przeciwnym razie otrzymasz wyjątek ObjectDisposed. – Zerowalker

+0

@ user2587718 To naprawdę zależy od typu obiektu itp. Zaleciłbym zadać własne pytanie dotyczące tego. –

2

Nawet miałem ten sam problem i zorientowaliśmy się, że najlepszym sposobem, aby go rozwiązać jest stworzenie Rezygnacja tokena źródło nowo tuż przed wywołaniem metody.

to co robię na moim przycisk Start kliknij:

cancellationTokenSource = new CancellationTokenSource(); 
cancellationToken = cancellationTokenSource.Token; 
Task.Factory.StartNew(StartUpload, cancellationToken); 

zmienić podpis do tego samego przycisku, aby anulować i po jednym kliknięciu pojawia się na anulowanie wzywam

cancellationTokenSource.Cancel(); 

Tutaj to pełny kod:

if (button3.Text != "&Start Upload") 
     { 
      cancellationTokenSource.Cancel(); 
     } 
     else 
     { 
      try 
      { 
       cancellationTokenSource = new CancellationTokenSource(); 
       cancellationToken = cancellationTokenSource.Token; 
       Task.Factory.StartNew(StartUpload, cancellationToken); 
      } 
      catch (AggregateException ex) 
      { 
       var builder = new StringBuilder(); 
       foreach (var v in ex.InnerExceptions) 
        builder.Append("\r\n" + v.InnerException); 
       MessageBox.Show("There was an exception:\r\n" + builder.ToString()); 
      } 
      catch (Exception ex) 
      { 
       MessageBox.Show(ex.Message); 
      } 
     }