TOC

This article has been localized into Italian by the community.

Controlli misti:

Il controllo ProgressBar

WPF viene fornito con un comodo controllo per la visualizzazione dell'avanzamento, chiamato ProgressBar. Funziona impostando un valore minimo e massimo e quindi incrementando un valore, che fornirà un'indicazione visiva sullo stato attuale di avanzamento nel processo. Ecco un esempio molto semplice per dimostrarne le funzioni:

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

In questo caso, si e' utilizzato un approccio piuttosto standard per mostrare i progressi in percentuale (tra 0 e 100%), partendo da un valore iniziale di 75. Un altro approccio consiste nell'utilizzare i valori minimo e massimo effettivi da un elenco di attività che si stanno eseguendo. Ad esempio, se si scorre un elenco di file raccolti durante il controllo di ciascuno di essi, è possibile impostare la proprietà 'Minimum' su 0 e la proprietà 'Maximum' sulla quantità di file nell'elenco e quindi incrementare attraverso un ciclo durante l'esecuzione.

Il Controllo 'ProgressBar' è, proprio come gli altri controlli WPF standard, in grado di adattarsi allo stile visivo del sistema operativo. Qui su Windows 7, ha un carino gradiente animato, come mostrato nello screenshot.

Mostrare l'avanzamento mentre si eseguono task lunghi

L'esempio di sopra mostra quanto sia semplice usare il 'ProgressBar', ma normalmente si vuole mostrare l'avanzamento di alcuni lavori effettivi e non solo un valore statico.

Nella maggior parte delle situazioni si utilizza il 'ProgressBar' per mostrare lo stato di avanzamento di alcune attività pesanti/lunghe, ed è qui che la maggior parte dei nuovi programmatori si imbatte in un problema comune: se si esegue un lavoro pesante sul thread dell'interfaccia utente, durante il tentativo di aggiornare contemporaneamente, ad es. un controllo 'ProgressBar', ci si rende subito conto che non si possono fare entrambe le cose, allo stesso tempo, sullo stesso thread. Per essere più chiari, e' possibile falro, ma il 'ProgressBar' non mostrerà effettivamente ogni aggiornamento prima che il task e' completato, il che lo rende praticamente inutile.

Per illustrare il problema, potete provare il seguente esempio:

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

Un esempio molto semplice, in cui, non appena la finestra è pronta, eseguiamo un ciclo da 0 a 100 e in ogni iterazione, incrementiamo il valore del 'ProgressBar'. Qualsiasi computer moderno può farlo più velocemente di quanto si possa battere le palpebre, quindi abbiamo aggiunto un ritardo a ogni iterazione di 100 millisecondi. Sfortunatamente, come già descritto, non succederà nulla. Ecco come appare il controllo nel mezzo del processo:

Si noti che il cursore indica che sta succedendo qualcosa, ma il 'ProgressBar' sembra ancora come all'inizio (vuoto). Non appena il ciclo, che rappresenta il nostro lungo compito, è completato, il 'ProgressBar' avrà questo aspetto:

Questo non ha davvero aiutato i tuoi utenti a vedere l'avanzamento! Perche' l'avanzamento sia visibile, invece, dobbiamo eseguire l'attività su un thread di lavoro e quindi inviare gli aggiornamenti al thread dell'interfaccia utente, che sarà quindi in grado di elaborare immediatamente e mostrare visivamente questi aggiornamenti. Uno strumento eccellente per gestire questo lavoro è la classe 'BackgroundWorker', di cui parleremo più approfonditamente altrove in questo tutorial. Ecco lo stesso esempio di cui sopra, ma questa volta usando un '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;
		}
	}
}

Come si vede nello screenshot, l'avanzamento viene ora aggiornato completamente attraverso il task e come indica il cursore, non viene eseguito alcun duro lavoro sul thread dell'interfaccia utente, il che significa che è ancora possibile interagire con il resto dell'interfaccia.

Si tenga presente che mentre il 'BackgroundWorker' aiuta molto con i problemi relativi al multithreading, ci sono ancora alcune cose di cui si deve essere a conoscenza, quindi diamo un'occhiata agli articoli di 'BackgroundWorker' in questo tutorial prima di fare qualcosa di più avanzato di uno scenario come quello sopra.

Indeterminato

Per alcune attività, non è possibile esprimere il progresso in percentuale o semplicemente non e' possibile sapere quanto tempo il processo impiegherà. Per quelle situazioni, è stata inventata una barra di avanzamento indeterminata, in cui un'animazione fa sapere all'utente che sta succedendo qualcosa, indicando che il tempo di esecuzione non può essere determinato.

La 'ProgressBar' WPF supporta questa modalità tramite l'uso della proprietà 'IsIndeterminate', che mostreremo nel prossimo esempio:

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

Notare che l'indicatore di progresso verde non è ancorato a nessuno dei lati, ma galleggia liberamente dall'inizio alla fine e quindi ricomincia ancora da capo.

ProgressBar con testo

Una cosa che e' sfuggita della ProgressBar standard di WPF è la possibilità di mostrare una rappresentazione testuale dell'avanzamento e della barra di avanzamento. Fortunatamente per noi, la flessibilità di WPF ci rende davvero facile realizzare questo obiettivo. Ecco un esempio:

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

Realizziamo quanto sopra mettendo un 'ProgressBar' e un 'TextBlock' che mostra la percentuale all'interno della stessa griglia, senza specificare alcuna riga o colonna. Questo visualizza il 'TextBlock' sopra la 'ProgressBar', che è esattamente quello che vogliamo qui, perché TextBlock ha uno sfondo trasparente per impostazione predefinita.

Utilizziamo un'associazione per assicurarci che il 'TextBlock' mostri lo stesso valore del 'ProgressBar'. Notare la sintassi speciale StringFormat, che ci consente di mostrare il valore con un segno di percentuale - potrebbe sembrare un po' strano, ma vi prego di leggere l'articolo StringFormat di questo tutorial per ulteriori informazioni al riguardo.


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!