Barwy postępu na żywo - seria Spectre Console
Biblioteka Spectre.Console służy do przekształcania zwykłych aplikacji konsolowych w języku C# w atrakcyjne wizualnie i bogate w informacje narzędzia. Jedną z najbardziej charakterystycznych funkcji jest możliwość wyświetlania pasków postępu, które aktualizują się w miarę działania aplikacji. Jest to niezwykle pomocne w przypadku długotrwałych zadań, w których chcesz na bieżąco informować użytkownika.
W swoim filmie "Live Progress Bars – Spectre Console Series" Tim Corey pokazuje krok po kroku, jak stworzyć pasek postępu w konsoli Spectre w języku C#.
Konfiguracja aplikacji konsolowej
Na początku filmu (0:00) Tim przedstawia bibliotekę konsoli Spectre.Console i pokazuje, że link do kodu źródłowego jest dostępny pod filmem. Przypomina widzom, że są to 10-minutowe fragmenty, które można wpasować w swój dzień.
Tim pracuje w zwykłej aplikacji konsolowej napisanej w języku C# — wyobraź sobie prosty szablonowy plik z klasą Program i statyczną metodą void Main(string[] args). Nie korzysta on z żadnego specjalnego frameworka UI, a jedynie z odwołania do pakietu NuGet Spectre.Console. Warto pamiętać, że funkcje te można wykorzystać w dowolnym terminalu Windows lub hostingu konsoli.
Tworzenie kontekstu postępu
O 0:34 Tim zaczyna pisać kod. W swojej metodzie Main wywołuje on AnsiConsole.Progress(), a następnie .Start(). Jest to standardowy punkt wejścia dla paska postępu w Spectre.Console.
Pokazuje on, że przekazujesz lambdę z parametrem kontekstowym, który możesz traktować jako async ctx, gdy później uczynisz ją asynchroniczną. W tym kontekście definiujesz swoje zadania. Jest to odpowiednik Spectre.Console, polegający na skonfigurowaniu zadań postępu przed rozpoczęciem ich aktualizacji.
Dodawanie zadań postępu
Tim tworzy trzy zadania związane z postępami prac:
-
"Pobieranie danych"
-
"Instalowanie aplikacji"
- "Czyszczenie danych"
Każde z nich jest dodawane za pomocą var task = context.AddTask("…"). Te identyfikatory zadań zwrotnych można później zwiększać. Tim zauważa (1:22), że to dopiero wierzchołek góry lodowej — Spectre.Console obsługuje różne style, kolumny i układy, takie jak dodawanie nowych kolumn ProgressBarColumn, PercentageColumn, SpinnerColumn lub TaskDescriptionColumn w celu dostosowania wyglądu paska.
Porównuje te zadania do instalatora Visual Studio: pobieranie, instalacja, a następnie czyszczenie (1:42). Można sobie wyobrazić, że każde zadanie przechowuje wewnętrznie wartość typu int percent lub int podczas aktualizacji.
Aktualizacja pasków postępu
O 1:50 Tim konfiguruje pętlę while, która będzie działać do momentu zakończenia kontekstu. W prawdziwym programie konsolowym w języku C można napisać while (!context.IsFinished) lub while (context.IsFinished == false) wewnątrz metody Main.
W pętli wywołuje Thread.Sleep(500), aby spowolnić działanie (2:15). Następnie wywołuje metodę task.Increment() z losową wartością typu double pomnożoną przez wartość maksymalną (2:29, 2:47). To symuluje wykonywaną pracę.
Aktualizuje zadanie pierwsze i zadanie drugie z różną prędkością, a w zadaniu trzecim dodaje warunek if (3:05), tak aby zadanie to rozpoczęło się dopiero wtedy, gdy procent wykonania zadania drugiego przekroczy 80. Jest to w zasadzie sterowanie zależnościami między zadaniami postępu.
Chociaż Tim nie wpisuje dosłownie int i w pętli foreach, można sobie wyobrazić użycie takiej pętli do iteracji nad zadaniami i wywołania .Increment(int) dla każdego z nich. W środowisku produkcyjnym mogą występować rzeczywiste dane, takie jak klient typu var pobierający pliki lub przetwarzana nazwa pliku w postaci ciągu znaków. Tim upraszcza sprawę, używając losowych liczb do pokazania wyświetlacza.
Wyświetlanie i obserwowanie pasków postępu
O 3:47 Tim uruchamia aplikację konsolową. Paski postępu są wyświetlane jeden nad drugim. Każdy pasek pokazuje na końcu wartość procentową i zmienia kolor na zielony po zakończeniu (4:01). Po wykonaniu pierwszych zadań rozpoczyna się "oczyszczanie danych".
O 4:14 Tim zwraca uwagę, że kursor wraca na dół konsoli, co jest drobnym, ale ważnym szczegółem wpływającym na użyteczność. Pasek postępu Spectre.Console automatycznie formatuje status i utrzymuje wszystko na swoim miejscu bez migotania.
Przejście na tryb asynchroniczny za pomocą Await Task
O 4:36 Tim zmienia temat, aby pokazać wersję asynchroniczną. Zmienia .Start() na .StartAsync() i oznacza lambdę jako asynchroniczną. Teraz parametr context zachowuje się jak async ctx.
Wewnątrz, zamiast Thread.Sleep używa await Task.Delay(500) (4:58). Dzięki temu podczas oczekiwania kontrola wraca do systemu. W rzeczywistym programie można oczekiwać rzeczywistej operacji, takiej jak await client.DownloadAsync() lub await AnsiConsole.MarkupAsync(), aby wydrukować tekst statusu obok paska.
Wersja asynchroniczna działa dokładnie tak samo pod względem wizualnym (5:16–5:23), ale jest lepiej dostosowana do nowoczesnych przepływów pracy asynchronicznej. Tim tego nie pokazuje, ale można również przechwytywać wyjątki za pomocą try/catch (Exception ex) wokół zadań oczekiwanych.

AutoClear i zakończenie
Tim zauważa, że domyślnie Spectre.Console pozostawia ukończone zadania na ekranie w 100%. Jeśli chcesz, aby znikały automatycznie, wywołaj .AutoClear(true) po skonfigurowaniu postępu (5:42). Po zakończeniu pracy paski znikają natychmiast (6:02).

Jest to przydatne, gdy chcesz tylko tymczasowo wyświetlić raport o postępach i nie chcesz zaśmiećać wyjścia konsoli. W połączeniu z interaktywnymi podpowiedziąmi, nowymi wyświetlaczami panelowymi, a nawet tabelą zmiennych z Spectre.Console, można stworzyć dynamiczny interfejs użytkownika konsoli w stylu pulpitu nawigacyjnego.
Więcej niż podstawy – różne style i kolumny
W końcowych minutach Tim wspomina (6:11), że jest jeszcze wiele do odkrycia. Możesz zmieniać format, kolory, układy i używać różnych typów kolumn. Na przykład możesz dodać nowy wykres słupkowy (BarChart), nową tabelę (Table) lub połączyć nowy panel (Panel) z paskami postępu, aby wyświetlić zgrupowane wyniki.
Dokumentacja Spectre.Console pokazuje, jak włączyć nowe implementacje ProgressColumn, dostosować maksymalną wartość każdego zadania, a nawet złożyć wiele zadań w jeden pasek w celu zaoszczędzenia miejsca ("folding space"). Można ich używać do wyświetlania liczb, sum, nazw plików, nazw użytkowników lub haseł będących w trakcie przetwarzania — wszystko to w estetycznym formacie w aplikacji konsolowej.
Wnioski
Tim w swoim filmie omówił:
-
Pasek postępu konsoli Spectre zbudowany od podstaw
-
Jak definiować i aktualizować wiele zadań w toku
-
Jak uruchomić to synchronicznie za pomocą Thread.Sleep lub asynchronicznie za pomocą await Task.Delay
-
Jak używać .AutoClear(true) do czyszczenia ukończonych pasków
- Gdzie szukać bardziej zaawansowanych stylów i dokumentacji
To krótkie demo pokazuje, jak łatwo można wstawić profesjonalnie wyglądające paski postępu do dowolnego programu konsolowego w języku C#. Wystarczy pakiet NuGet Spectre.Console i kilka linii kodu, aby wyświetlać status, pokazywać wartości procentowe i zapewnić użytkownikom znacznie jaśniejszy obraz działania aplikacji.
