26

He estado jugando con el async ctp esta mañana y tengo un programa simple con un button y un label. Haga clic en button y comienza a actualizar el label, detenga el button y deja de escribir en label. Sin embargo, no estoy seguro de cómo restablecer el CancellationTokenSource para que pueda reiniciar el proceso. Mi código es el siguiente:¿Cómo reinicio un CancellationToken correctamente?

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

¿Es C# 5.0? No compila en .NET 4.0 – Fulproof

+0

aún puede obtener el ctp para 4.0. Sin embargo, sí, esta es una función 4.5 – poco

Respuesta

51

necesita volver a crear la CancellationTokenSource - no hay manera de "reset" una vez que establezca.

Esto podría ser tan simple como:

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

¿Cuándo se supone que debe deshacerse de ella al cerrar la aplicación? Como tiene que esperar antes de que termine el subproceso, de lo contrario obtendrá la excepción ObjectDisposed. – Zerowalker

+0

@ user2587718 Realmente depende del tipo de objeto, etc. Le recomendaría hacer su propia pregunta al respecto. –

2

Incluso tenía el mismo problema y lo he descubierto que, mejor manera de resolverlo es crear la cancelación de origen Token recién justo antes de llamar al método.

esto es lo que hago en mi botón de arranque clic:

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

puedo cambiar el título para el mismo botón para cancelar y cuando ocurre un clic sobre Cancelar, llamo

cancellationTokenSource.Cancel(); 

Aquí es el código completo:

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); 
      } 
     } 
Cuestiones relacionadas