This article has been localized into German by the community.
Das ProgressBar Steuerelement
WPF hat ein praktisches Bedienelement um einen Fortschritt darzustellen und zwar den ProgressBar. Er funktioniert indem man einen minimalen und einen maximalen Wert einstellt und dann einen Wert hochzählt, was dem Nutzer einen sichtbaren Hinweis geben wird wie weit der Prozess schon fortgeschritten ist. Hier ist ein sehr simples Beispiel zur Demonstration:
<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 diesem Fall habe ich eine sehr standardmäßige Herangehensweise benutzt um den Fortschritt als Prozente (zwischen 0 und 100%), mit einem Ausgangswert von 75, anzuzeigen. Eine andere Methode ist es tatsächlich die minimalen und maximalen Werte einer Liste von Aufgaben zu nehmen, die ausgeführt wird. Zum Beispiel könntest du, wenn du mit einer Schleife durch eine Liste mit gesammelten Dateien springst und diese überprüfst, den Minimum Wert auf 0 setzen und den Maximum Wert auf die Anzahl der Dateien aus der Liste, während du den Wert bei jedem Schleifendurchlauf erhöhst.
Der ProgressBar wird, genau wie die anderen standardmäßigen Steuerelemente von WPF, passend zu dem grafischen Stil des Betriebssystems gerendert. In diesem Fall ist es Windows 7, was einen schönen animierten Farbverlauf hat, wie man auf der Abbildung sehen kann.
Anzeige des Forschritts währen einer langandauernden Aufgabe
Das oben gezeigte Beispiel zeigt wie einfach es sein kann einen ProgressBar zu benutzen, aber normalerweise will man natürlich einen Fortschritt einer tatsächlichen Arbeit anzeigen lassen und keinen statischen Wert.
In den meisten Situation werden Sie den ProgressBar benutzen, um den Fortschritt einer schweren/langandauernden Aufgabe anzuzeigen und das ist genau der Punkt an dem die meisten neuen Programmierer in ein bekanntes Problem laufen: Wenn man einen Teil einer schweren Aufgabe auf dem UI Thread ausführt und währendessen versucht gleichzeitig z.B. das ProgrssBar Steuerelement upzudaten, wird schnell klar werden, dass man nicht beides zur gleichen Zeit auf dem selben Thread ausführen kann. Oder um es deutlicher zu machen, man kann schon, aber der ProgressBar wird den Fortschritt nicht anzeigen bevor nicht die Aufgabe erledigt ist, was die ganze Sache ziemlich sinnlos macht.
Um das Gesagte zu veranschaulichen können Sie folgendes Beispiel ausprobieren:
<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);
}
}
}
}
Ein sehr einfaches Beispiel ist es, sobald das Fenster bereit ist, eine Schleife zu starten die von 0 bis 100 zählt und in jedem Durchlauf wird der Wert des ProgressBar um eins erhöht. Jeder moderne Computer kann das schneller machen als Sie blinzeln können, also habe ich eine Verzögerung von 100 Millisekunden zu jedem Schleifendurchlauf hinzugefügt. Leider, wie ich bereits beschrieben habe, passiert nichts. So sieht es inmitten des Prozesses aus:
Es fällt auf, dass der Mauszeiger anzeigt, dass etwas passiert, aber der ProgressBar sieht noch genau so aus wie zu Beginn (leer). Sobald unsere Schleife, die unseren langandauernden Prozess repräsentiert, fertig ist, sieht der ProgressBar so aus:
Das hilft nun wirklich nicht dem Benutzer zu sehen wie weit der Fortschritt ist! Stattdessen müssen wir die Aufgabe auf einem Arbeitsthread ausführen und dann das UI Thread updaten, welches dann dazu fähig ist den Prozess sofort auszuführen und den Forschritt anzuzeigen. Ein perfektes Tool um diese Arbeit auszuführen ist die BackgroundWorker Klasse, worüber genauer in einem anderen Teil dieses Tutorial geredet wird. Hier ist das gleiche Beispiel wie oben, aber dieses Mal mit dem 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;
}
}
}
Wie man auf dem Screenshot sehen kann, wird der Fortschritt jetzt während der Ausführung des gesamten Prozesses aktualisiert und der Mauzeiger signalisiert, dass keine harte Arbeit auf dem UI Thread ausgeführt wird. Somit kann man also immernoch mit der Oberfläche interagieren.
Bitte beachten Sie, dass der BackgroundWorker zwar sehr bei Problemen das Multithreading betreffend helfen kann, es sind aber noch genug Dinge die beachtet werden müssen, also schauen Sie sich bitte die Artikel des BackgroundWorkers in diesem Tutorial an bevor Sie etwas komplizierteres probieren als das Szenario weiter oben.
Unbestimmte Dauer
Bei manchen Aufgaben ist es nicht möglich den Fortschritt in Prozenten darzustellen oder man weiß einfach nicht wie lange sie dauern. Für diese Situationen wurde der unbestimmte ProgressBar erfunden, bei dem eine Animation den Benutzer wissen lässt, dass etwas passiert, während er anzeigt, dass die Prozesszeit nicht ermittelt werden kann.
Der WPF ProgressBar unterstützt diesen Modus durch die Eigenschaft IsIndeterminate, die in dem nächsten Beispiel gezeigt wird:
<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>
Wie man sehen kann liegt der Grüne Indikator an keiner der Seiten an - stattdessen fließt er frei von links nach rechts und startet dann wieder von vorne.
ProgressBar mit Text
Eine Sache die ich an dem Standard WPF ProgressBar wirklich vermisst habe, ist die Fähigkeit den Fortschritt sowohl als Balken als auch als Text anzuzeigen. Glückerweise erlaubt uns die Flexibilität von WPF diese Sache sehr einfach einzufügen. Hier ist ein Beispiel:
<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>
Wir haben das oben abgebildet erreicht, indem wir den ProgressBar und den TextBlock, der die Prozentanzahl zeigt, in den gleichen Grid packen, ohne irgendwelche Reihen oder Spalten zu definieren. Das rendert den Textblock genau über den ProgressBar, was genau das ist was wir wollen, da der TextBlock standardmäßig einen durchsichtigen Hintergrund hat.
Wir benutzen ein Binding um sicherzustellen, dass der TextBlock das gleiche zeigt wie der ProgressBar. Beachten Sie die spezielle StringFormat syntax, die uns erlaubt den Wert mit dem Prozentzeichen anzuzeigen - es sieht vielleicht etwas seltsam aus, aber bitte schauen Sie sich den StringFormatArtikel in diesem Tutorial an, um mehr Informationen darüber zu erhalten.