TOC

This article has been localized into Portuguese by the community.

Misc.:

Cancelando o BackgroundWorker

Como vimos no artigo anterior, o multi-threading tem a vantagem adicional de poder mostrar progresso e não ter seu aplicativo travado durante a operação demorada.

Outro problema que você enfrentará se realizar todo o trabalho no thread da interface do usuário é o fato de que não há como o usuário cancelar uma tarefa em execução - e por que isso acontece? Porque, se o thread da interface do usuário estiver ocupado realizando sua tarefa demorada, nenhuma entrada será processada, o que significa que não importa o quanto o usuário pressione o botão Cancelar ou a tecla Esc, nada acontece.

Felizmente para nós, o BackgroundWorker foi criado para facilitar o suporte ao progresso e cancelamento, e enquanto analisamos toda a parte do progresso no capítulo anterior, este será sobre como usar o suporte de cancelamento. Vamos pular direto para um exemplo:

<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;
			}
		}
	}
}

Portanto, o XAML é muito fundamental - apenas um rótulo para mostrar o status atual e, em seguida, alguns botões para iniciar e cancelar o trabalhador.

Em Code-behind, começamos criando a instância BackgroundWorker. Preste especial atenção às propriedades WorkerSupportsCancellation e WorkerReportsProgress que definimos como verdadeiras - sem isso, uma exceção será lançada se tentarmos usar esses recursos.

O botão cancelar simplesmente chama o método CancelAsync () - isso sinalizará ao funcionário que o usuário gostaria de cancelar o processo em execução definindo a propriedade CancellationPending como true, mas isso é tudo o que você pode fazer no thread da interface do usuário - o restante terá que ser feito dentro do evento DoWork .

No evento DoWork , contamos até 100 com um atraso de 250 milissegundos em cada iteração. Isso nos dá uma boa e longa tarefa, para a qual podemos relatar o progresso e ainda ter tempo de acertar o botão Cancelar.

Observe como eu verifico a propriedade CancellationPending em cada iteração - se o trabalhador for cancelado, essa propriedade será verdadeira e terei a oportunidade de sair do loop. Eu defino a propriedade Cancelar nos argumentos do evento, para sinalizar que o processo foi cancelado - esse valor é usado no evento RunWorkerCompleted para ver se o trabalhador realmente foi concluído ou se foi cancelado.

No evento RunWorkerCompleted , basta verificar se o trabalhador foi cancelado ou não e atualizar o rótulo de status de acordo.

Resumo

Então, para resumir, adicionar suporte de cancelamento ao seu BackgroundWorker é fácil - apenas certifique-se de definir a propriedade WorkerSupportsCancellation como true e verifique a propriedade CancellationPending ao executar o trabalho. Então, quando você quiser cancelar a tarefa, basta chamar o método CancelAsync () no worker e pronto.


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!