TOC

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

Controles diversos:

The ProgressBar control

O WPF vem com um controle prático para exibir o progresso, chamado de ProgressBar . Ele funciona definindo um valor mínimo e máximo e, em seguida, incrementando um valor, o que dará uma indicação visual de até onde você está no processo. Aqui está um exemplo muito básico para demonstrar isso com:

<Window x:Class="WpfTutorialSamples.Misc_controls.ProgressBarSample"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="ProgressBarSample" Height="100" Width="300">
    <Grid Margin="20">
        <ProgressBar Minimum="0" Maximum="100" Value="75" />
    </Grid>
</Window>

Neste caso, usei uma abordagem bastante padrão de mostrar o progresso como uma porcentagem (entre 0 e 100%), dando-lhe um valor inicial de 75. Outra abordagem é usar valores mínimos e máximos reais em uma lista de tarefas que você está se apresentando. Por exemplo, se você percorrer uma lista coletada de arquivos durante a verificação de cada um deles, poderá definir a propriedade Mínimo como 0, o Máximo com a quantidade de arquivos em sua lista e, em seguida, apenas incrementá-lo conforme percorrê-lo.

O ProgressBar é, assim como outros controles padrão do WPF, processado para corresponder ao estilo visual do sistema operacional. Aqui no Windows 7, ele tem um bom gradiente animado, como visto na captura de tela.

Mostrando progresso ao executar uma tarefa demorada

O exemplo acima ilustra como é simples usar uma ProgressBar, mas normalmente você deseja mostrar o progresso de algum trabalho real e não apenas um valor estático.

Na maioria das situações, você usará a ProgressBar para mostrar o progresso de alguma tarefa pesada / demorada, e é nesse ponto que a maioria dos novos programadores se depara com um problema muito comum: se você faz um trabalho pesado no thread da interface, tentando simultaneamente atualizar por exemplo um controle ProgressBar, você logo perceberá que não pode fazer as duas coisas, ao mesmo tempo, no mesmo thread. Ou, para ser mais claro, você pode, mas a ProgressBar não mostrará cada atualização do progresso antes que a tarefa seja concluída, o que praticamente a torna inútil.

Para ilustrar, você pode tentar o seguinte exemplo:

<Window x:Class="WpfTutorialSamples.Misc_controls.ProgressBarTaskOnUiThread"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="ProgressBarTaskOnUiThread" Height="100" Width="300"
        ContentRendered="Window_ContentRendered">
    <Grid Margin="20">
        <ProgressBar Minimum="0" Maximum="100" Name="pbStatus" />
    </Grid>
</Window>
using System;
using System.Threading;
using System.Windows;

namespace WpfTutorialSamples.Misc_controls
{
	public partial class ProgressBarTaskOnUiThread : Window
	{
		public ProgressBarTaskOnUiThread()
		{
			InitializeComponent();
		}

		private void Window_ContentRendered(object sender, EventArgs e)
		{
			for(int i = 0; i < 100; i++)
			{
				pbStatus.Value++;
				Thread.Sleep(100);
			}
		}
	}
}

Um exemplo muito básico, em que, assim que a janela está pronta, fazemos um loop de 0 a 100 e, em cada iteração, incrementamos o valor da ProgressBar. Qualquer computador moderno pode fazer isso mais rápido do que você pode piscar os olhos, então eu adicionei um atraso para cada iteração de 100 milissegundos. Infelizmente, como já descrevi, nada vai acontecer. É assim que fica no meio do processo:

Observe que o cursor indica que algo está acontecendo, mas o ProgressBar ainda parece ter sido no início (vazio). Assim que o loop, que representa nossa longa tarefa, estiver concluído, o ProgressBar ficará assim:

Isso realmente não ajudou seus usuários a ver o progresso! Em vez disso, temos que executar a tarefa em um thread de trabalho e, em seguida, enviar atualizações para o thread da interface do usuário, que poderá processar imediatamente e exibir visualmente essas atualizações. Uma excelente ferramenta para lidar com esse trabalho é a classe BackgroundWorker, sobre a qual falamos muito mais sobre este tutorial. Aqui está o mesmo exemplo acima, mas desta vez usando um BackgroundWorker:

<Window x:Class="WpfTutorialSamples.Misc_controls.ProgressBarTaskOnWorkerThread"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="ProgressBarTaskOnWorkerThread" Height="100" Width="300"
        ContentRendered="Window_ContentRendered">
    <Grid Margin="20">
        <ProgressBar Minimum="0" Maximum="100" Name="pbStatus" />
    </Grid>
</Window>
using System;
using System.ComponentModel;
using System.Threading;
using System.Windows;

namespace WpfTutorialSamples.Misc_controls
{
	public partial class ProgressBarTaskOnWorkerThread : Window
	{
		public ProgressBarTaskOnWorkerThread()
		{
			InitializeComponent();
		}

		private void Window_ContentRendered(object sender, EventArgs e)
		{
			BackgroundWorker worker = new BackgroundWorker();
			worker.WorkerReportsProgress = true;
			worker.DoWork += worker_DoWork;
			worker.ProgressChanged += worker_ProgressChanged;

			worker.RunWorkerAsync();
		}

		void worker_DoWork(object sender, DoWorkEventArgs e)
		{
			for(int i = 0; i < 100; i++)
			{
				(sender as BackgroundWorker).ReportProgress(i);
				Thread.Sleep(100);
			}
		}

		void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
		{
			pbStatus.Value = e.ProgressPercentage;
		}
	}
}

Como você pode ver na captura de tela, o progresso agora é atualizado durante toda a tarefa e, como o cursor indica, nenhum trabalho pesado está sendo realizado no thread da interface do usuário, o que significa que você ainda pode interagir com o restante da interface .

Esteja ciente de que, embora o BackgroundWorker ajude muito com problemas relacionados a multithreading, ainda há algumas coisas que você deve conhecer, portanto, dê uma olhada nos artigos do BackgroundWorker neste tutorial antes de fazer algo mais avançado do que um cenário como o acima.

Indeterminado

Para algumas tarefas, expressar o progresso como uma porcentagem não é possível ou você simplesmente não sabe quanto tempo levará. Para essas situações, a barra de progresso indeterminada foi inventada, onde uma animação permite que o usuário saiba que algo está acontecendo, enquanto indica que o tempo de execução não pode ser determinado.

O WPF ProgressBar suporta este modo através do uso da propriedade IsIndeterminate, que mostraremos no próximo exemplo:

<Window x:Class="WpfTutorialSamples.Misc_controls.ProgressBarIndeterminateSample"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="ProgressBarIndeterminateSample" Height="100" Width="300">
    <Grid Margin="20">
        <ProgressBar Minimum="0" Maximum="100" Name="pbStatus" IsIndeterminate="True" />
    </Grid>
</Window>

Observe que o indicador de progresso verde não está ancorado em nenhum dos lados - em vez disso, ele flutua livremente do início ao fim e, em seguida, começa tudo de novo.

ProgressBar com texto

Uma coisa que eu realmente perdi do ProgressBar padrão do WPF é a capacidade de mostrar uma representação de texto do progresso, bem como a barra de progresso. Felizmente para nós, a flexibilidade do WPF torna isso realmente fácil de realizar. Aqui está um exemplo:

<Window x:Class="WpfTutorialSamples.Misc_controls.ProgressBarTextSample"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="ProgressBarTextSample" Height="100" Width="300">
    <Grid Margin="20">
        <ProgressBar Minimum="0" Maximum="100" Value="75" Name="pbStatus" />
        <TextBlock Text="{Binding ElementName=pbStatus, Path=Value, StringFormat={}{0:0}%}" HorizontalAlignment="Center" VerticalAlignment="Center" />
    </Grid>
</Window>

Realizamos o acima, colocando o ProgressBar e o TextBlock mostrando a porcentagem dentro da mesma Grade, sem especificar nenhuma linha ou coluna. Isso renderizará o TextBlock sobre o ProgressBar, que é exatamente o que queremos aqui, porque o TextBlock tem um fundo transparente por padrão.

Usamos uma ligação para garantir que o TextBlock mostre o mesmo valor da ProgressBar. Observe a sintaxe especial StringFormat , que nos permite mostrar o valor com um postfixo de sinal de porcentagem - pode parecer um pouco estranho, mas veja o artigo StringFormat deste tutorial para mais informações sobre isso.


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!