This article has been localized into Italian by the community.
Annullamento di BackgroundWorker
Come abbiamo visto nel precedente articolo, il multi-thread ha il vantaggio aggiuntivo di essere in grado di mostrare i progressi e di non bloccare l'applicazione mentre si esegue un'operazione che richiede tempo.
Un altro problema che dovrai affrontare se eseguirai tutto il lavoro sul thread dell'interfaccia utente è il fatto che l'utente non può annullare un'attività in esecuzione. Perché? Perché se il thread dell'interfaccia utente è occupato nell'esecuzione di una lunga attività, nessun input verrà elaborato, il che significa che, indipendentemente dalla forza con cui l'utente preme il pulsante Annulla o il tasto Esc, non accade nulla.
Fortunatamente per noi, BackgroundWorker è stato creato per semplificare il supporto dell'avanzamento e dell'annullamento e, mentre abbiamo esaminato l'intera parte relativa allo stato di avanzamento nel capitolo precedente, questo sarà interamente su come utilizzare il supporto di annullamento. Passiamo direttamente a un esempio:
<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;
}
}
}
}
Quindi, XAML è minimale: solo un'etichetta per mostrare lo stato corrente e poi un paio di pulsanti per avviare e cancellare il lavoratore.
In Code-behind, iniziamo creando l'istanza di BackgroundWorker. Presta particolare attenzione alle proprietà WorkerSupportsCancellation e WorkerReportsProgress che impostiamo su true - senza di ciò, verrà generata un'eccezione se proviamo a utilizzare queste funzionalità.
Il pulsante Annulla chiama semplicemente il metodo CancelAsync() - questo segnalerà al lavoratore che l'utente vorrebbe annullare l'esecuzione processo impostando la proprietà CancelPending su true, ma è il massimo che puoi fare dal thread dell'interfaccia utente: il resto dovrà essere fatto dall'interno dell'evento DoWork .
Nell'evento DoWork , contiamo fino a 100 con un ritardo di 250 millisecondi su ogni iterazione. Questo ci dà un compito lungo, durante il quale possiamo segnalare i progressi e avere ancora tempo per premere il pulsante Annulla.
Nota che controllo la proprietà CancellationPending su ogni iterazione: se il worker viene annullato, questa proprietà sarà true e avrò l'opportunità di uscire dal ciclo. Ho impostato la proprietà Cancel sugli argomenti dell'evento, per segnalare che il processo è stato annullato - questo valore viene utilizzato nell'evento RunWorkerCompleted per verificare se il worker è stato effettivamente completato o se è stato annullato.
Nell'evento RunWorkerCompleted , controllo semplicemente se il worker è stato annullato o meno e quindi aggiorno l'etichetta di stato di conseguenza.
Sommario
Quindi, per riassumere, aggiungere il supporto per la cancellazione di BackgroundWorker è semplice: assicurati di impostare WorkerSupportsCancellation su true e controlla la proprietà CancelPending durante l'esecuzione del lavoro. Quindi, quando si desidera annullare l'attività, è sufficiente chiamare il metodo CancelAsync () sul worker e il gioco è fatto.