This document captures the design and implementation details of ProgressTaskGroup and its related types (ProgressTask, ProgressTaskColumn, ProgressTaskColumns).
For end-user usage and examples, see ProgressTaskGroup.
Grid, TextBlock, ProgressBar, Spinner) instead of custom rendering.ProgressTaskGroup is a Visual with:
Tasks : BindableList<ProgressTask> (bindable getter)Columns : BindableList<ProgressTaskColumn> (bindable getter)
ProgressTaskGroupStyle.DefaultColumnsDefaults:
HorizontalAlignment = Align.StretchVerticalAlignment = Align.StartProgressTask is a state container (not a Visual) and implements IVisualElement so it can participate in the binding dirty model when hosted by a control:
Label : Visual - label visual (a ComputedVisual can be used when constructed with Func<Visual>).Value : double (bindable)Minimum : double (bindable)Maximum : double (bindable, default is 1.0)Progress01 : double - normalized progress in [0..1]Percentage : int - progress in [0..100]Increment(double delta) convenience helper.Task cell customization:
CustomizeCell(columnId, Action<Visual>) adds an unkeyed customization.SetCellCustomization(columnId, key, Action<Visual>) replaces (columnId,key) customization.ClearCellCustomizations(columnId) removes all customizations for that column.OnCellCreated(columnId, cell) is called by the group for columns that have an Id and applies registered customizations.ProgressTaskColumn describes one column:
CellFactory : Func<ProgressTask, Visual> (required)Id : string? (optional, used for task customization hooks)Width : GridLength (default Auto)MinWidth : intMaxWidth : int (default int.MaxValue)ProgressTaskColumns provides built-in columns and stable ids:
LabelColumnId, BarColumnId, PercentageColumnId, SpinnerColumnIdLabel(Align alignment = Align.End)Bar(ProgressBarStyle? style = null, int minWidth = 10)Percentage()Spinner(SpinnerStyle? style = null)The group uses ProgressTaskGroupStyle (src/XenoAtom.Terminal.UI/Styling/ProgressTaskGroupStyle.cs) for layout defaults:
DefaultColumns (label + bar + percentage by default)ColumnSpacing and RowSpacingEach built-in column uses its corresponding control styles:
ProgressBarStyle (default is ProgressBarStyle.Default)SpinnerStyle (default is SpinnerStyle.Default)Tests:
src/XenoAtom.Terminal.UI.Tests/ProgressTaskGroupRenderingTests.cs (label/percentage rendering, per-task bar styling)Demo:
samples/ControlsDemo/Demos/ProgressTaskGroupDemo.csUser documentation:
site/docs/controls/progresstaskgroup.mdInternally, ProgressTaskGroup hosts a single child ComputedVisual that builds the group content:
Build() returns a Grid that contains one row per task and one column per column definition.Tasks, Columns, or relevant style values change, the computed visual rebuilds the grid.This means:
ProgressTask.Value typically does not require rebuilding the grid, because the built-in column visuals bind to task properties (e.g. ProgressTask.Progress01).The grid is built with:
ColumnDefinition per effective column (and optional gap columns if ColumnSpacing > 0).RowDefinition per task (and optional gap rows if RowSpacing > 0).Row/column gaps are implemented by inserting additional fixed-size definitions between the real tracks (a stride of 2 when gaps are enabled).
For each (task, column):
ProgressTaskColumn.CellFactory(task) creates a Visual cell.Id, the group calls task.OnCellCreated(id, cell) before adding it to the grid.Built-in convenience customization (implemented via extension methods in ProgressTaskExtensions.cs):
task.StyleBar(style) applies a ProgressBarStyle to the bar cell created by ProgressTaskColumns.Bar().task.StyleSpinner(style) applies a SpinnerStyle to the spinner cell created by ProgressTaskColumns.Spinner().ProgressTaskGroup is display-only and does not handle keyboard/mouse input or expose commands.
Grid or wrapper visuals).