Come cancellare un compito in attesa?

Sto giocando con questi task WinRT di Windows 8 e sto tentando di annullare un’attività utilizzando il metodo seguente, e funziona fino a un certo punto. Viene chiamato il metodo CancelNotification, che ti fa pensare che l’attività sia stata annullata, ma in background l’attività continua a funzionare, quindi, una volta completata, lo stato dell’attività è sempre completato e mai annullato. C’è un modo per fermare completamente l’attività quando viene annullata?

private async void TryTask() { CancellationTokenSource source = new CancellationTokenSource(); source.Token.Register(CancelNotification); source.CancelAfter(TimeSpan.FromSeconds(1)); var task = Task.Factory.StartNew(() => slowFunc(1, 2), source.Token); await task; if (task.IsCompleted) { MessageDialog md = new MessageDialog(task.Result.ToString()); await md.ShowAsync(); } else { MessageDialog md = new MessageDialog("Uncompleted"); await md.ShowAsync(); } } private int slowFunc(int a, int b) { string someString = string.Empty; for (int i = 0; i < 200000; i++) { someString += "a"; } return a + b; } private void CancelNotification() { } 

Leggi su Annullamento (che è stato introdotto in .NET 4.0 ed è in gran parte invariato da allora) e il pattern asincrono basato su attività , che fornisce le linee guida su come usare CancellationToken con metodi async .

Per riassumere, si passa un CancellationToken in ogni metodo che supporta la cancellazione e tale metodo deve controllarlo periodicamente.

 private async Task TryTask() { CancellationTokenSource source = new CancellationTokenSource(); source.CancelAfter(TimeSpan.FromSeconds(1)); Task task = Task.Run(() => slowFunc(1, 2, source.Token), source.Token); // (A canceled task will raise an exception when awaited). await task; } private int slowFunc(int a, int b, CancellationToken cancellationToken) { string someString = string.Empty; for (int i = 0; i < 200000; i++) { someString += "a"; if (i % 1000 == 0) cancellationToken.ThrowIfCancellationRequested(); } return a + b; } 

Oppure, per evitare di modificare slowFunc (diciamo che non si ha accesso al codice sorgente per esempio):

 var source = new CancellationTokenSource(); //original code source.Token.Register(CancelNotification); //original code source.CancelAfter(TimeSpan.FromSeconds(1)); //original code var completionSource = new TaskCompletionSource(); //New code source.Token.Register(() => completionSource.TrySetCanceled()); //New code var task = Task.Factory.StartNew(() => slowFunc(1, 2), source.Token); //original code //original code: await task; await Task.WhenAny(task, completionSource.Task); //New code 

Puoi anche usare i buoni metodi di estensione da https://github.com/StephenCleary/AsyncEx e avere un aspetto semplice come:

 await Task.WhenAny(task, source.Token.AsTask()); 

Voglio solo aggiungere alla risposta già accettata. Ero bloccato su questo, ma stavo andando a un altro percorso sulla gestione dell’evento completo. Invece di aspettare, aggiungo un handler completato all’attività.

 Comments.AsAsyncAction().Completed += new AsyncActionCompletedHandler(CommentLoadComplete); 

Dove il gestore di eventi si presenta così

 private void CommentLoadComplete(IAsyncAction sender, AsyncStatus status ) { if (status == AsyncStatus.Canceled) { return; } CommentsItemsControl.ItemsSource = Comments.Result; CommentScrollViewer.ScrollToVerticalOffset(0); CommentScrollViewer.Visibility = Visibility.Visible; CommentProgressRing.Visibility = Visibility.Collapsed; } 

Con questo percorso, tutto il trattamento è già fatto per te, quando l’attività viene annullata, si triggers solo il gestore di eventi e puoi vedere se è stato cancellato lì.