TOC

This article is currently in the process of being translated into Italian (~97% done).

Misc.:

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.

Summary

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.

This article has been fully translated into the following languages: Is your preferred language not on the list? Click here to help us translate this article into your language!