Fortschritt im Icon der Taskleiste mit C# oder VB.NET anzeigen

Fortschritt im Icon der Taskleiste mit C# und VB.NET anzeigen
Fortschritt im Icon der Taskleiste mit C# und VB.NET anzeigen

Um Fortschritt in der Taskleiste, bzw. im Icon der Taskleiste anzuzeigen, kannst Du z. B. bei WPF-Anwendungen die „TaskbarItemInfo“-Klasse verwenden. Setze einen passenden Zustand in die „ProgressState“-Eigenschaft (z. B. „Normal“) und einen entsprechenden Fortschritt via „ProgressValue“-Eigenschaft.

Eine ProgressBar in der Taskleiste? Nice!

Yes! Gerade eben bin ich mit den einzelnen Teilen meines aktuellen YouTube-Videos fertig geworden. Und jetzt? Naja, jetzt muss ich das Ganze noch schneiden! Dazu verwende ich immer das bekannte Programm „DaVinci Resolve“. Alles zurechtgerückt und geschnitten, startete ich also im nächsten Schritt den Render-Prozess und da kam es mir in den Kopf!

Wenn Du es eilig hast, kannst Du natürlich die obigen Kapitel aus dem Inhaltsverzeichnis nutzen. Springe zum Beispiel hier zum WPF- und hier zum Windows Forms Beispiel.

In der Taskleiste sah ich die Fortschrittsanzeige (ProgressBar), Welche unter dem Taskleisten-Icon angezeigt wird. An der Stelle habe ich mich dann gefragt: „Öhm, hast Du als YouTuber im Bereich .NET überhaupt schon ein Tutorial dazu gemacht?“. Die Antwort war – nein! Also begann ich im nächsten Schritt direkt mit diesem Beitrag hier, wozu auch bald darauf das Video erscheinen wird.

Im Videoformat

Zu viel Text? Keine Sorge, schaue Dir einfach das passende YouTube-Video auf meinem Kanal an. So kannst Du Dir alles in Ruhe anschauen und Dich berieseln lassen. Ich rate Dir dennoch – zumindest ergänzend zum Beitrag – da ich hier nochmal alles im Detail erkläre.

Ein Beispiel

Wie gleich folgend könnte es z. B. in Deinem Programm (bei mir unter Windows 11) aussehen. Ich habe (wie Du unten noch sehen wirst) den Fortschritt jede Sekunde erhöht. Das hat natürlich zur Folge, dass diese kleine Fortschrittsbalken unter dem Icon wächst.

Fortschrittsanzeige in der Taskleiste unter .NET
Fortschrittsanzeige in der Taskleiste unter .NET

Besonders für Rendering-Softwares oder Programmen mit ähnlich langen Prozessen meines Erachtens nach unabdingbar! Alternativ gibt es auch noch eine Art „ich bin einfach busy“-Status, also wenn man den genauen Fortschritt vielleicht nicht darstellen kann.

Die TaskBarInfo-Klasse in WPF

Fortschrittsanzeige ProgressBar mit Csharp oder VB.NET in der Taskleiste anzeigen - WPF
Fortschrittsanzeige ProgressBar mit Csharp oder VB.NET in der Taskleiste anzeigen – WPF

Um unser Vorhaben, also eine Fortschrittsanzeige unter dem Programm-Icon in der Taskleiste umzusetzen, gibt es von WPF einfache Bordmittel. Hierbei handelt es sich um die „TaskbarItemInfo“-Klasse, Welche sich im „System.Windows.Shell“-Namespace versteckt. Diese, bzw. Instanzen davon bieten verschiedene Eigenschaften an, die wir mit passenden Werten versehen können.

Eine Fortschrittsanzeige zum Fenster hinzufügen

Um überhaupt eine Art Fortschritt anzeigen zu können, müssen wir erstmal eine passende Instanz der jeweiligen Klasse erstellen. Danach muss diese Instanz der passenden Window-Eigenschaft zugewiesen werden. Dadurch weiß das WPF-Fenster: „Aha, meine Info finde ich also da..“. Klingt kompliziert, ist aber eigentlich ganz einfach.

In typischer WPF-Manier, sprich im XAML-Code, sieht das dann wie gleich folgend aus. Problem ist nur, dass Du aktuell praktisch immer „30%“ als Fortschritt sehen würdest. Das liegt natürlich daran, dass wir den Wert für die „ProgressValue“-Eigenschaft hard gecoded haben.

<Window x:Class="blabla.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800" Loaded="Window_Loaded">
    
    <Window.TaskbarItemInfo>
        <TaskbarItemInfo ProgressState="Normal" ProgressValue="0.3" />
    </Window.TaskbarItemInfo>
   
    <Grid>

    </Grid>
</Window>

Mögliche Zustände

Im nächsten Schritt können wir z. B. festlegen, was wir eigentlich darstellen möchten, z. B. eine Art Fehler im Vorgang. Oder wollen wir einfach nur den „normalen“ Fortschritt darstellen? Das machen wir mit der „ProgressState“-Eigenschaft, der „TaskbarItemInfo“-Klasse. Die gängigen Werte kannst Du hier nachlesen:

  • None
  • Normal
  • Indeterminate
  • Paused
  • Error

Je nach Einstellung färbt sich die Fortschrittsanzeige in der Taskleiste dementsprechend. Ebenso haben wir dadurch die Möglichkeit, die ProgressBar zu deaktivieren, sowie auf eine Art „auf unbestimmte Dauer beschäftigt“ zu setzen. Für Letzteres ist z. B. der Zustand „Indeterminate“ gedacht.

Fortschritt verändern

Das obige Beispiel dürfte wie schon erwähnt relativ langweilig sein, da unser Fortschritt nur auf einer Stelle stehenbleibt. Gehen wir also nun die Fortschritts-Veränderung an, dazu brauchen wir nur die passende Eigenschaft im Code verändern. Beachte, dass „20%“ z. B. „0,2“ wären, nicht „20“!

Beachte ebenso, dass wir Zustandsveränderungen nur auf dem Thread der grafischen Oberfläche durchführen sollten. Ansonsten wirst Du vermutlich eine Cross-Thread Fehlermeldung bekommen! Schaue Dir zu diesem Thema gerne auch meinen „Beitrag zu ConfigureAwait“ und den Beitrag zum Thema „Ungültiger threadübergreifender Vorgang“ an.

Mit der „Thread-Kenntnis“ starten wir nun eine einfach „Fire and Forget“-Task, Welche den Fortschritt immer wieder nach kurzer Verzögerung anpasst. Dadurch, dass „ConfigureAwait“ standardmäßig auf „true“ steht, brauchen wir uns hier keine Gedanken über den Thread der Oberfläche machen. Denn so hüpfen wir immer wieder in den Ursprungs-Kontext = die grafische Oberfläche (um’s einfach zu halten..).

Generiere im nächsten Schritt einfach einen „Loaded“-Ereignishandler, indem Du innerhalb des Window-Tags „Loaded“ schreibst und dann Tab drückst. In den Bereich des Loaded-Handlers kannst Du dann folgenden Code unterbringen:

// sonstiger Fenster-Code

    private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        _ = SimulateProgress();
    }

    private async Task SimulateProgress()
    {
        while (TaskbarItemInfo.ProgressValue < 1)
        {
            await Task.Delay(1000);
            TaskbarItemInfo.ProgressValue += 0.1;
        }
        Debug.WriteLine("completed!");
        TaskbarItemInfo.ProgressState = System.Windows.Shell.TaskbarItemProgressState.None;
    }

// sonstiger Fenster-Code
' sonstiger Fenster-Code

Private Sub Window_Loaded(sender As Object, e As RoutedEventArgs)
    Dim fireAndForgetTask = SimulateProgress()
End Sub

Private Async Function SimulateProgress() As Task
    While TaskbarItemInfo.ProgressValue < 1
        Await Task.Delay(1000)
        TaskbarItemInfo.ProgressValue += 0.1
    End While

    Debug.WriteLine("completed!")
    TaskbarItemInfo.ProgressState = System.Windows.Shell.TaskbarItemProgressState.None
End Function

' sonstiger Fenster-Code

Sobald das Fenster geladen ist, zeigen wir die ProgressBar an, denn wir haben Sie im MainWindow XAML-Code sichtbar geschaltet! Danach beginnt der Code von „SimulateProgress“ zu wirken. Wir warten letztendlich immer 1 Sekunde (solange wir nicht bei 100% sind). Und erhöhen dann die Fortschrittsanzeige um 10%. Wenn wir fertig sind, geben wir dies in einer kleinen Debug-Zeile aus und schalten die Fortschrittsanzeige aus.

Im Gegensatz zu vielen anderen Online-Codes, verzichte ich hier auf einen BackgroundWorker, dessen Benutzung Du gerne in meinem Background Worker Guide erfahren kannst. Ich bevorzuge die gezeigte Variante, wo wir eine einfache Task verwenden :).

Für Windows Forms

Fortschrittsanzeige ProgressBar mit Csharp oder VB.NET in der Taskleiste anzeigen - Windows Forms
Fortschrittsanzeige ProgressBar mit Csharp oder VB.NET in der Taskleiste anzeigen – Windows Forms

Wenn Du im Gegensatz zum obigen Beispiel die guten alten Windows Forms verwendest, bist Du hier natürlich ebenfalls genau richtig! Im Endeffekt ist die Verwendung der TaskBar und die darin befindlichen in Winforms nicht sooo viel schwerer. Das einzige Problem ist zunächst, dass Du auf „die TaskBar“ keinen so einfachen Zugriff hast.

Paket installieren

Um einen einfachen Zugriff auf die TaskBar zu erhalten, installierst Du einfach erst einmal folgendes Paket. Öffne dazu (wie so häufig im .NET-Bereich) den NuGet Paket-Manager. Dies kannst Du z. B. durch einen Rechtsklick auf Dein Projekt und dem passenden Menüeintrag machen. Entweder führst Du dann den unteren Befehl in der NuGet Konsole aus, oder suchst via GUI manuell nach dem Paket „WindowsAPICodePack-Shell“.

Install-Package WindowsAPICodePack-Shell

Mögliche Zustände

Nach der Installation des oben angegebenen Paketes, kannst Du analog zu den Zuständen oben, Ebendiese schalten. Diese befinden sich in einer Enumeration namens „TaskbarProgressBarState“.

Um zu einem jeweiligen Zustand zu schalten, verwendest Du nun die „SetProgressState“-Methode der „TaskbarManager“-Klasse, bzw. dessen „Instance“-Eigenschaft. Somit kannst Du nun zwischen den verschiedenen Modi wie „NoProgress“, „Indeterminate“ und mehr, hin und her schalten. Normal heißt auch hier: „Zeige einen Fortschritt an“.

TaskbarManager.Instance.SetProgressState(TaskbarProgressBarState.Normal, Handle)

Fortschritt verändern

Um den Fortschritt der Taskbar-ProgressBar nun zu verändern, kannst Du die analoge „SetProgressValue“-Methode verwenden. Hier setze ich z. B. „20%“ von „100%“ als aktuellen Wert:

TaskbarManager.Instance.SetProgressValue(20, 100, Handle)

Fortschritt ausblenden

Möchtest Du den Fortschritt wieder ausblenden, verwendest Du einfach dies hier:

TaskbarManager.Instance.SetProgressState(TaskbarProgressBarState.NoProgress, Handle)

Achtung: Bekannte Stolpersteine

Als ich das erste Mal mit der Thematik „ProgressBar in Taskleiste“ in Verbindung kam, hatte ich zumindest bei Windows Forms Projekten einige Probleme. Zuerst einmal fehlte die jeweilig verwendete Klasse und dann blieb der Aufruf wirkungslos, seufz.. Z. B. Folgendes ging nicht:

TaskbarManager.Instance.SetProgressState(TaskbarProgressBarState.Normal)

Das falsche Paket

Mit ein wenig Gefummel, habe ich dann rausbekommen, dass ich das falsche Paket installiert hatte, bzw. nicht alles. Ich hatte das „WindowsAPICodePack-Core“ installiert, allerdings hatte ich da keine Klasse namens „TaskbarManager“, auf die ich zugreifen, geschweige denn importieren konnte. Achte daher darauf, dass Du das korrekte Paket namens „WindowsAPICodePack-Shell“ installierst! Dann kannst Du zumindest die genannte Klasse namens „TaskbarManager“ verwenden.

Fehlendes Handle

Im nächsten Schritt stieß ich auf das Problem, dass die Aufrufe an sich durchgingen, aber irgendwie keine Wirkung hatten. Hier und da ein wenig rumprobiert, schon stieß ich auch auf die diesbezügliche Lösung: Man muss beim Aufruf ein Form-Handle angeben! Das Form-Handle der jeweiligen Form, für die ich eine ProgressBar in der Taskleiste anzeigen möchte. Gesagt, getan – aus Aufruf ohne Handle, wurde ein Aufruf mit Handle:

TaskbarManager.Instance.SetProgressValue(<currentValue>, <maxValue>, Handle)

Beachte hierbei, dass ich diesen Code aus der Form selbst aufrufe, nur deshalb habe ich hier den einfachen Zugriff auf dessen „Handle“-Eigenschaft!

Fehlende PresentationFramework Assembly

Die letzte Hürde ließ nicht lange auf sich warten, denn der geänderte Aufruf führte zu folgendem Fehler:

"Fehler: Es ist ein Verweis auf die Assembly PresentationFramework erforderlich. Fügen Sie dem Projekt einen Verweis hinzu."
„Fehler: Es ist ein Verweis auf die Assembly PresentationFramework erforderlich. Fügen Sie dem Projekt einen Verweis hinzu.“

Auch dieser Fehler ist relativ einfach zu lösen! Mache einen Rechtsklick auf Dein Projekt, klicke auf Projektdatei bearbeiten, und füge die „UseWPF->True“ Konfiguration im Bild hinzu:

NET Projektdatei - UseWpf auf true
NET Projektdatei – UseWpf auf true

Downloads

Hast Du keine Lust alles händisch nachzubauen? Kein Problem, lade Dir doch einfach die gebrauchsfertigen Projekte herunter ;)!

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert