This article has been localized into French by the community.
Annuler le BackgroundWorker
Comme nous l'avons vu dans l'article précédent, le multi-threading à en plus l'avantage d'être capable de montrer la progression sans que votre application n'attende alors que vous réalisez une opération chronophage.
Un autre problème que vous rencontrerez si vous réalisez tout le travail sur le thread de l'interface utilisateur est qu'il ne restera alors aucun moyen laissé à l'utilisateur pour annuler la tâche. Et pourquoi ça ? Parce que si le thread de l'interface utilisateur est occupée avec une tâche longue, aucune entrée ne sera traitée, ce qui signifie que peu importe à quel point l'utilisateur appuie sur le bouton Cancel ou Échap., rien ne se passera.
Heureusement pour nous, le BackgroundWorker est conçu pour rendre le support du suivi de la progression et l'annulation faciles. Alors que nous avons évoqué l'ensemble de la partie sur le suivi de la progression dans le chapitre précédent, celui-ci sera entièrement consacré à la manière d'utiliser le support de l'annulation. Regardons tout de suite un exemple:
<Window x:Class="WpfTutorialSamples.Misc.BackgroundWorkerCancellationSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="BackgroundWorkerCancellationSample" Height="120" Width="200">
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center">
<TextBlock Name="lblStatus" HorizontalAlignment="Center" Margin="0,10" FontWeight="Bold">Not running...</TextBlock>
<WrapPanel>
<Button Name="btnStart" Width="60" Margin="10,0" Click="btnStart_Click">Start</Button>
<Button Name="btnCancel" Width="60" Click="btnCancel_Click">Cancel</Button>
</WrapPanel>
</StackPanel>
</Window>
using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Media;
namespace WpfTutorialSamples.Misc
{
public partial class BackgroundWorkerCancellationSample : Window
{
private BackgroundWorker worker = null;
public BackgroundWorkerCancellationSample()
{
InitializeComponent();
worker = new BackgroundWorker();
worker.WorkerSupportsCancellation = true;
worker.WorkerReportsProgress = true;
worker.DoWork += worker_DoWork;
worker.ProgressChanged += worker_ProgressChanged;
worker.RunWorkerCompleted += worker_RunWorkerCompleted;
}
private void btnStart_Click(object sender, RoutedEventArgs e)
{
worker.RunWorkerAsync();
}
private void btnCancel_Click(object sender, RoutedEventArgs e)
{
worker.CancelAsync();
}
void worker_DoWork(object sender, DoWorkEventArgs e)
{
for(int i = 0; i <= 100; i++)
{
if(worker.CancellationPending == true)
{
e.Cancel = true;
return;
}
worker.ReportProgress(i);
System.Threading.Thread.Sleep(250);
}
e.Result = 42;
}
void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
lblStatus.Text = "Working... (" + e.ProgressPercentage + "%)";
}
void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if(e.Cancelled)
{
lblStatus.Foreground = Brushes.Red;
lblStatus.Text = "Cancelled by user...";
}
else
{
lblStatus.Foreground = Brushes.Green;
lblStatus.Text = "Done... Calc result: " + e.Result;
}
}
}
}
Le code XAML est très simple. Juste un label pour montrer le statut actuel et quelques boutons pour démarrer et annuler le worker.
Dans le code-behind, nous commençons par instancier un BackgroundWorker. Portez une attention particulière aux propriétés WorkerSupportsCancellation et WorkerReportsProgress que nous définissons à true. Sans cela, une exception surviendra si nous essayons d'utiliser ces fonctionnalités.
Le bouton cancel appelle simplement la méthode CancelAsync(). Cela signale au worker que l'utilisateur souhaite en annuler l'exécution en passant sa propriété CancellationPending à true, mais c'est là tout ce que vous pouvez faire depuis le thread de l'interface utilisateur. Le reste devra être fait depuis l'événementDoWork.
Dans l'event DoWork, dans une boucle for, nous comptons jusqu'à 100 avec une attente de 250 milliseconde pour chaque itération. Cela nous donne une tâche bien longue pour laquelle nous pouvons rapporter un suivi de progression tout en ayant le temps d'appuyer sur le bouton Cancel.
Notez comment je vérifie la propriété CancellationPending sur chaque itération. Si le worker est annulé, cette propriété sera alors true et j'aurais l'opportunité de sortir de la boucle. Je définis la propriété Cancel sur l'argument de l'event pour signaler que le processus a été stoppé. Celle valeur est utilisé dans l'évènement RunWorkerCompleted pour voir si le worker à terminé ou si il a été annulé.
Dans l'évènement RunWorkerCompleted, je vérifie simplement si le worker à été annulé ou pas et je mets ensuite à jour le statut du label en conformité.
Résumé
Pour résumer, ajouter le support de l'annulation dans votre BackgroundWorker est aisé. Assurez vous simplement de bien définir la propriété WorkerSupportsCancellation à true et vérifiez la propriété CancellationPending lors de la réalisation du travail. Ensuite, quand vous voulez annuler la tâche, il suffit d'appeler la méthode CancelAsync() sur le worker et le tour est joué.