Table of Contents

Class FormControl

Namespace
SharpConsoleUI.Controls
Assembly
SharpConsoleUI.dll

A labeled-input form: a two-column grid (label | editor) that composes real input controls.

public class FormControl : GridControl, IDOMPaintable, INotifyPropertyChanged, IContainer, IContainerControl, IControlHost, IColorRoleableControl, IGridSource, IFillReportsMinimumHeight, IInteractiveControl, IFocusableControl, IMouseAwareControl, IWindowControl, IDisposable, IFocusScope, ILogicalCursorProvider, ICursorShapeProvider
Inheritance
FormControl
Implements
Inherited Members
Extension Methods

Remarks

FormControl is an honest subclass of GridControl — it adds no custom paint or measure. Each field is a real MarkupControl label placed in column 0 and a real input control (e.g. PromptControl, CheckboxControl) placed in column 1, via the inherited Place(IWindowControl, int, int, int, int). The layout, focus, and rendering are the grid's; the form only wires up fields and value getters.

Column 0 is Auto(int?, int?) (sized to the widest label); column 1 is Star(double, int?, int?) (takes the remaining width). One row is added per field.

Value access is AOT-safe: each field carries a plain Func<TResult> getter — no reflection. GetValues() invokes every getter to produce a name→value snapshot.

Constructors

FormControl()

Initializes a new, empty form with a two-column grid: an auto-sized label column and a star-sized editor column, with no gap between rows.

public FormControl()

Properties

ValidateOnChange

When true, each field re-validates itself as soon as its editor's value changes (live validation). Fields whose editor exposes no value-changed event are validated only by Validate() / Submit().

public bool ValidateOnChange { get; set; }

Property Value

bool

Remarks

Setting this to true subscribes all existing and future fields to their editor's native change event where one exists: InputChanged, ContentChanged, CheckedChanged, SelectedValueChanged, ValueChanged, and SelectionChanged.

Methods

AddCheckbox(string, string, bool, string?)

Adds a boolean field backed by a CheckboxControl. The checkbox carries its own label in the editor column, so the form's label column is left empty for this field.

public FormControl AddCheckbox(string name, string label, bool initial = false, string? hint = null)

Parameters

name string

The field key.

label string

The checkbox's own label (shown in the editor column).

initial bool

The initial checked state.

hint string

Optional dim hint text shown beneath the editor.

Returns

FormControl

This form, for fluent chaining. The value is "true"/"false".

AddDropdown(string, string, IEnumerable<string>, string?, string?, int?, HorizontalAlignment?)

Adds a single-select field backed by a DropdownControl.

public FormControl AddDropdown(string name, string label, IEnumerable<string> options, string? initial = null, string? hint = null, int? width = null, HorizontalAlignment? align = null)

Parameters

name string

The field key.

label string

The label text.

options IEnumerable<string>

The selectable options.

initial string

The initially selected option, or null for none.

hint string

Optional dim hint text shown beneath the editor.

width int?

Optional fixed editor width in columns. When null (the default), the dropdown auto-fits to its content (the ▾ arrow sits snug after the selected value); when set, its width is fixed at this value.

align HorizontalAlignment?

Optional explicit horizontal alignment that overrides the field's default (dropdown auto-fits, i.e. left-aligned at natural width). When null (the default), the smart default applies. When set, it wins over the auto-fit default (e.g. Stretch to fill the cell).

Returns

FormControl

This form, for fluent chaining.

AddField(string, string, IWindowControl, Func<string?>, Func<string?, string?>?, bool, string?)

Adds a field with a caller-supplied editor and value getter — the escape hatch used by the typed overloads and by callers needing a control this form does not build itself.

public FormControl AddField(string name, string label, IWindowControl editor, Func<string?> valueGetter, Func<string?, string?>? validate = null, bool required = false, string? hint = null)

Parameters

name string

The field key (used in GetValues() and GetEditor(string)).

label string

The label text (escaped before display).

editor IWindowControl

The control to place in the editor column.

valueGetter Func<string>

A delegate that reads the editor's current value.

validate Func<string, string>

Optional validator (reserved; applied in a later task).

required bool

Whether the field is required (reserved; applied in a later task).

hint string

Optional dim hint text shown beneath the editor.

Returns

FormControl

This form, for fluent chaining.

AddMultilineEdit(string, string, string, int, string?, int?, HorizontalAlignment?)

Adds a multi-line text field backed by a MultilineEditControl.

public FormControl AddMultilineEdit(string name, string label, string initial = "", int height = 3, string? hint = null, int? width = null, HorizontalAlignment? align = null)

Parameters

name string

The field key.

label string

The label text.

initial string

The initial content.

height int

The editor's viewport height in rows.

hint string

Optional dim hint text shown beneath the editor.

width int?

Optional fixed editor width in columns. When null (the default), the editor stretches to fill the star editor cell; when set, the editor width is fixed at this value and does not stretch.

align HorizontalAlignment?

Optional explicit horizontal alignment that overrides the field's default (multiline stretches to fill). When null (the default), the smart default applies. When set, it wins over the stretch default; an explicit width may be combined with it.

Returns

FormControl

This form, for fluent chaining.

AddRadio(string, string, params string[])

Adds a string radio field where each option is both its own value and display label.

public FormControl AddRadio(string name, string label, params string[] options)

Parameters

name string

The field key.

label string

The label text.

options string[]

The option strings (value = label).

Returns

FormControl

This form, for fluent chaining.

AddRadio<T>(string, string, IEnumerable<(T Value, string Label)>, string?, int?, HorizontalAlignment?)

Adds a typed single-select field rendered as a group of radios. The radios are hosted in a borderless PanelControl placed in the editor cell, while GetEditor(string) returns the typed RadioGroup<T> so callers can read/write SelectedValue.

public FormControl AddRadio<T>(string name, string label, IEnumerable<(T Value, string Label)> options, string? hint = null, int? width = null, HorizontalAlignment? align = null)

Parameters

name string

The field key.

label string

The label text.

options IEnumerable<(T Value, string Label)>

The (value, display-label) option pairs.

hint string

Optional dim hint text shown beneath the editor.

width int?

Optional fixed width in columns for the hosting radio panel. When null (the default), the radio group takes its natural (left-packed) width — radios are not stretched to fill, as a filled radio group reads oddly. When set, the hosting panel width is fixed at this value.

align HorizontalAlignment?

Optional explicit horizontal alignment that overrides the field's default (radio panel keeps its natural, left-packed width). When null (the default), the smart default applies. When set, it is applied to the hosting panel (e.g. Stretch to fill the cell); an explicit width may be combined with it.

Returns

FormControl

This form, for fluent chaining.

Type Parameters

T

The option value type.

AddRow(params Action<FormControl>[])

Adds several fields onto a single grid row, packed side by side. Each adder runs against this form while a row-packing context is active, so the field it adds is placed on the shared row in the next label/editor column pair (field i → columns 2i/2i+1) instead of a new row.

public FormControl AddRow(params Action<FormControl>[] fieldAdders)

Parameters

fieldAdders Action<FormControl>[]

The per-field add callbacks (e.g. f => f.AddText(...)), one per column.

Returns

FormControl

This form, for fluent chaining.

Remarks

This is the only path that widens the grid beyond its two base columns: extra Auto(int?, int?) label / Star(double, int?, int?) editor column pairs are added as needed. After all adders run, single-field-per-row placement is restored and the row advances. The packed fields are tracked as one row-group (see SharpConsoleUI.Controls.FormControl.RowGroupCountForTest()). Fields stay packed side by side regardless of width; responsive stacking on narrow terminals is a planned follow-up (a wrap layout the form will compose).

AddSection(string?, bool, bool)

Starts a collapsible field group as a full-width header row in the same flat grid. Every field added after this call (until the next AddSection(string?, bool, bool)) belongs to this section, so a collapsible section can hide/show all its fields together.

public FormControl AddSection(string? title, bool collapsible = false, bool startCollapsed = false)

Parameters

title string

The section title (escaped and bolded), or null to end the current section.

collapsible bool

When true, a toggle button is rendered that hides/shows the section's fields.

startCollapsed bool

When true (and collapsible), the section's fields start hidden and the glyph starts ▸.

Returns

FormControl

This form, for fluent chaining.

Remarks

A section is not a nested panel: the header is a title MarkupControl in column 0 and (when collapsible) a ▸/▾ toggle ButtonControl in column 1, both on one grid row. Collapsing toggles Visible on each member field's controls. Pass a null title to end the current section: following fields belong to none.

AddSlider(string, string, double, double, double, string?, int?, HorizontalAlignment?)

Adds a numeric field backed by a SliderControl.

public FormControl AddSlider(string name, string label, double min, double max, double initial, string? hint = null, int? width = null, HorizontalAlignment? align = null)

Parameters

name string

The field key.

label string

The label text.

min double

The slider minimum.

max double

The slider maximum.

initial double

The initial value.

hint string

Optional dim hint text shown beneath the editor.

width int?

Optional fixed editor width in columns. When null (the default), the slider stretches to fill the star editor cell; when set, its width is fixed at this value and does not stretch.

align HorizontalAlignment?

Optional explicit horizontal alignment that overrides the field's default (slider stretches to fill). When null (the default), the smart default applies. When set, it wins over the stretch default; an explicit width may be combined with it.

Returns

FormControl

This form, for fluent chaining. The value is the number's string form.

AddText(string, string, string, Func<string?, string?>?, bool, string?, int?, HorizontalAlignment?)

Adds a single-line text field backed by a PromptControl.

public FormControl AddText(string name, string label, string initial = "", Func<string?, string?>? validate = null, bool required = false, string? hint = null, int? width = null, HorizontalAlignment? align = null)

Parameters

name string

The field key.

label string

The label text.

initial string

The initial text value.

validate Func<string, string>

Optional validator run on the field's current text.

required bool

Whether the field is required (empty text fails validation).

hint string

Optional dim hint text shown beneath the editor.

width int?

Optional fixed input width in columns. When null (the default), the editor stretches to fill the star editor cell; when set, the input area is fixed at this width and does not stretch.

align HorizontalAlignment?

Optional explicit horizontal alignment that overrides the field's default (text stretches to fill). When null (the default), the smart default applies. When set, it wins over the stretch default; an explicit width may be combined with it (e.g. a fixed width, right-aligned).

Returns

FormControl

This form, for fluent chaining.

Cancel()

Raises the Cancelled event.

public void Cancel()

GetEditor(string)

Gets the value-editor for a field: the placed input control for most fields, or the typed RadioGroup<T> for radio fields (so callers get the typed selection surface).

public object GetEditor(string name)

Parameters

name string

The field key.

Returns

object

The field's value-editor object.

Exceptions

KeyNotFoundException

Thrown when no field with name exists.

GetValues()

Reads every field's current value into a name→value snapshot. AOT-safe: each value comes from the field's plain getter delegate.

public IReadOnlyDictionary<string, string?> GetValues()

Returns

IReadOnlyDictionary<string, string>

A read-only map of field name to current value.

Submit()

Validates the form and, if valid, raises Submitted with the current values snapshot.

public void Submit()

Validate()

Validates every field: a required field with an empty/null value fails with "Required"; otherwise the field's custom validator (if any) runs on its current value. Each field's error line is updated (shown with the message, or hidden when valid). Idempotent.

public bool Validate()

Returns

bool

true when every field is valid; otherwise false.

WithButtons(string, string, bool)

Adds a final, full-width row of right-aligned action buttons: an OK button (which submits the form) and, when showCancel is true, a Cancel button (which raises Cancelled). The buttons live in a right-aligned HorizontalGridControl placed col-spanning the whole form.

public FormControl WithButtons(string ok = "OK", string cancel = "Cancel", bool showCancel = true)

Parameters

ok string

The OK button caption.

cancel string

The Cancel button caption.

showCancel bool

Whether to include the Cancel button.

Returns

FormControl

This form, for fluent chaining.

Remarks

Call this LAST, after any AddRow that widens the grid: the button row's col-span is fixed at call time to the current ColumnDefinitions count, so adding columns afterwards would leave the button row short of the form's full width.

Events

Cancelled

Raised when the form is cancelled (e.g. by a Cancel button wired in a later task).

public event EventHandler? Cancelled

Event Type

EventHandler

Submitted

Raised by Submit() when validation passes; carries the current values snapshot.

public event EventHandler<IReadOnlyDictionary<string, string?>>? Submitted

Event Type

EventHandler<IReadOnlyDictionary<string, string>>