ColumnDefinition<T> class Core

Typed, declarative description of ONE grid column — the consumer-facing API.

A GridView turns a list of these into its internal drawing model and erases Func<T,…> to Func<object,…> ONCE at build time; concrete return types mean no per-frame boxing.

Built via the fluent Column factory. Sort, filter and grouping all key off the element id the view assigns, so reordering columns never breaks them.

public sealed class ColumnDefinition<T> : IColumnDefinition, IColumnCell
Namespace
ArionUI.Presentation
Package
ArionUI.Presentation · dotnet add package ArionUI.Presentation --prerelease
Implements
IColumnDefinition, IColumnCell

Constructors

ColumnDefinition

public ColumnDefinition();

Properties

AccessibleText

public Func<T, string>? AccessibleText { get; set; }

What a screen reader SPEAKS for this cell (null = the display text). See ColumnDefinition.SpeakAs.

Align

public TextAlign Align { get; set; }

BadgeColor

public Func<T, Rgba>? BadgeColor { get; set; }

BadgeLabel

public Func<T, string>? BadgeLabel { get; set; }

BandPath

public IReadOnlyList<string>? BandPath { get; set; }

Banded-header grouping path (outermost first) — see ColumnDefinition.Band.

ButtonLabel

public Func<T, string>? ButtonLabel { get; set; }

CheckboxGet

public Func<T, bool>? CheckboxGet { get; set; }

CheckboxSet

public Action<T, bool>? CheckboxSet { get; set; }

CheckboxState

public Func<T, bool?>? CheckboxState { get; set; }

Optional tri-state getter for the drawn checkbox: null result = indeterminate (dash). Wins over ColumnDefinition.CheckboxGet for DRAWING; a "(select all)" row uses it. Toggle still goes through the click handler.

Composition

public SlotEl? Composition { get; set; }

Composed cell: a SlotEl tree drawn as the whole cell content — wins over the simple kinds above. Built via the typed Cell factory (Row/Stack/Text/Badge/Tag/Button/ Progress/Spacer).

CompositionInset

public double? CompositionInset { get; set; }

Horizontal inset of a COMPOSED cell's content box; null = the theme's cell padding. Chip/icon-button columns set 0: their composition IS a boxed control that budgets its own margins, and the default padding would push its overflow under the neighbour cell's background.

CustomSummaries

public List<string> CustomSummaries { get; }

Labels of the custom aggregates currently shown (footer and groups).

CustomSummaryOptions

public List<AggregateSpec> CustomSummaryOptions { get; }

Custom aggregates this column offers (median, distinct count, a weighted mean): each an AggregateSpec with a Custom delegate, keyed by its label. They run in the footer and per group over the same path as the built-in ones and appear in the Σ menu under their label.

DataType

public ColumnDataType? DataType { get; set; }

Value kind of the column — drives the filter-operator set (text matching vs. numeric/date comparison). Null = infer: Number when a numeric projection (ColumnDefinition.SummaryValue) exists, else Text.

DateCommitFormat

public string? DateCommitFormat { get; set; }

.NET date format the calendar COMMITS the picked day with (the column's setter must parse it). Null = the culture short-date ("d").

DateEditor

public bool DateEditor { get; set; }

Edit this column via a CALENDAR picker (see ColumnDefinition.WithDateEditor).

DateValue

public Func<T, DateTime?>? DateValue { get; set; }

Current date value for the calendar's initial selection (else the display text is parsed). Only used when ColumnDefinition.DateEditor is set.

public DropDownButtonMode DropDownButton { get; set; }

When the ▾ dropdown button shows in a combo/date cell (hover by default). A single click on the button opens the picker.

public DropDownStyle DropDownStyle { get; set; }

Look of the combo picker for this column (menu vs. classic).

EditOptions

public Func<T, IReadOnlyList<string>>? EditOptions { get; set; }

Fixed choices for the editor (combo picker). Null = free text.

EditText

public Func<T, string>? EditText { get; set; }

Raw text the EDITOR opens with (e.g. "1234.5" behind a display text of "1.234,50 €"). Null = the display text — fine for plain columns, wrong for formatted ones (the user would edit the formatting).

FillWeight

public double FillWeight { get; set; }

Star-sizing weight (0 = fixed). See ColumnDefinition.Fill.

Filterable

public bool Filterable { get; set; }

Every column with display text is filterable (filter cell, value list); ColumnDefinition.NotFilterable opts one out.

Groupable

public bool Groupable { get; set; }

GroupKey

public Func<T, object?>? GroupKey { get; set; }

Group bucket key (defaults to ColumnDefinition.SortKey).

GroupLabel

public Func<object?, string>? GroupLabel { get; set; }

Friendly label for a group's key value (defaults to ToString()).

public required string Header { get; init; }

Caption — the one thing every consumer of a column list needs without knowing the row type.

InputMask

public string? InputMask { get; set; }

Optional input mask for the editor (e.g. "00.00.0000"), or null for free text. See InputMask for the syntax.

IsExpander

public bool IsExpander { get; set; }

Master-detail expander column (chevron cell) — see Column.Expander.

IsNullable

public bool IsNullable { get; set; }

Allow the cell to be cleared to an empty value: an empty edit passes type validation (Number/Date) instead of being rejected, so the setter can store null. See ColumnDefinition.Nullable.

Key

public string? Key { get; }

Application-stable identity used by persisted layouts.

MaskPromptChar

public char MaskPromptChar { get; set; }

Prompt char shown at unfilled mask slots (default '_'). Set to ' ' (space) to hide the prompt — see ColumnDefinition.WithInputMask.

MaxTextLines

public int MaxTextLines { get; set; }

How many lines this column's text may wrap onto. 1 (the default) keeps the single-line behaviour. Above 1 the cell wraps and the last visible line is ellipsized — set a row height that fits, since the row does NOT grow to the content (a height that follows today's longest value moves the whole layout the moment the data changes).

PlainText

public Func<T, string>? PlainText { get; set; }

Plain-text projection of the cell for a column that draws no single label of its own (a composition, or a button-only cell). Supplies the text that filter-row "contains" matching and TSV copy need — the visual kinds (Text/Badge/Tag) already carry their own label.

RowType

public Type RowType { get; }

The row type this column was built for. A view checks it before accepting the column: a definition for the wrong type would draw and then fail on the first sort, which is a far worse failure than being rejected here.

Rules

public List<StyleRule> Rules { get; }

SelectAllOnEdit

public bool? SelectAllOnEdit { get; set; }

Per-column override of "select the whole content when the cell enters edit mode" (null = inherit the grid default). See ColumnDefinition.WithSelectAllOnEdit.

SetText

public Action<T, string>? SetText { get; set; }

Set ⇒ the column is editable; commit writes back through this.

SortComparer

public IComparer<object?>? SortComparer { get; set; }

Custom ordering of the sort keys — see ColumnDefinition.SortWith.

SortKey

public Func<T, object?>? SortKey { get; set; }

Set ⇒ sortable; also the default group key.

SummaryFns

public List<AggregateFn> SummaryFns { get; }

Aggregates shown for this column in the grand-total footer AND per group (Sum/Count/Avg/Min/Max — several at once, stacked). Empty ⇒ none. Mutable at runtime via the header Σ menu (GridView.ToggleSummary).

SummaryFormat

public Func<decimal, string>? SummaryFormat { get; set; }

Per-column text override (else the central ArionFormats.Summary default is used) — the per-column localization/formatting hook.

SummaryOptions

public List<AggregateFn>? SummaryOptions { get; set; }

Which aggregates the Σ menu OFFERS for this column (dev override). Null = the default: all five when ColumnDefinition.SummaryValue is set, otherwise none. Set e.g. to [Count] to offer Count on a text column, or to [Sum] to restrict a numeric column.

SummaryValue

public Func<T, decimal>? SummaryValue { get; set; }

Numeric value the value-aggregates (Sum/Avg/Min/Max) read. Not needed for Count. A column with this set is "summable" — the Σ menu offers all five; without it only Count is offered.

Tag

public object? Tag { get; set; }

Application data attached to the column — what a generated column MEANS. Never read by the grid; reachable via GridView.DefinitionByElementId.

TagColor

public Func<T, Rgba>? TagColor { get; set; }

TagLabel

public Func<T, string>? TagLabel { get; set; }

Text

public Func<T, string>? Text { get; set; }

Display text (text columns). Badge/tag/button columns use their own label instead.

TextOverflow

public TextOverflow? TextOverflow { get; set; }

Per-column overflow override; null = inherit the theme default (ArionTheme.CellTextOverflow). Set via ColumnDefinition.Ellipsis / ColumnDefinition.Clip.

Tooltip

public Func<T, double, string>? Tooltip { get; set; }

Per-column hover tooltip (null/empty = none). Without one, the grid still shows a truncated cell's full text; an app-level Presentation.CellTooltipProvider overrides both. What a CHART cell needs: its pixels truncate never, its DESCRIPTION belongs on hover.

Remarks

The second argument is the DATA POINT under the pointer (-1 = none) — which value of a sparkline, which segment of a stack. It comes from the same resolve that draws the point cursor, so the tooltip names exactly the value the line marks.

TreeLabel

public Func<T, string>? TreeLabel { get; set; }

TreeGrid hierarchy-column label projection — see Column.Tree.

ValidationMessage

public Func<string, string?>? ValidationMessage { get; set; }

Per-column edit validation: input text → error message (null = valid). Runs ON TOP of the data-type parse check; the editor shows the message and refuses to commit while one is returned.

Width

public double Width { get; set; }

Methods

Band

public ColumnDefinition<T> Band(params string[] path);

Group this column under a banded header (outermost segment first, e.g. .Band("KW 20", "Mo 11.05")). Adjacent columns sharing a path prefix render as one spanning band cell above the caption.

Center

public ColumnDefinition<T> Center();

ClassicDropDown

public ColumnDefinition<T> ClassicDropDown();

Render this column's combo picker in the classic framed look.

Clip

public ColumnDefinition<T> Clip();

Hard-clip over-wide text in this column at the cell edge.

Editable

public ColumnDefinition<T> Editable();

Mark the column editable WITHOUT a per-item setter — the commit is handled centrally (a TreeView cell-editor / spread callback). The editor opens; the value write goes through the interceptor.

Editable

public ColumnDefinition<T> Editable(Action<T, string> setter);

Ellipsis

public ColumnDefinition<T> Ellipsis();

Truncate over-wide text in this column with "…".

Fill

public ColumnDefinition<T> Fill(double weight = 1);

Star-sizing: this column takes the viewport width left over after the fixed columns (several fill columns share it by weight). ColumnDefinition.Width becomes the column's MINIMUM; a manual resize converts it back to fixed.

NotFilterable

public ColumnDefinition<T> NotFilterable();

Take the filter away from this column: no filter cell, no funnel, skipped by the filter-row keyboard walk.

Nullable

public ColumnDefinition<T> Nullable(bool value = true);

Mark the column nullable — an empty edit is valid (the setter receives "" and can store null). Without this a Number/Date column rejects empty input and reverts to the old value.

public ColumnDefinition<T> Right();

Searchable

public ColumnDefinition<T> Searchable(Func<T, string> text);

Give a composed/button column a plain-text projection so it can be filtered and copied (it draws no single label the grid could reuse).

Sortable

public ColumnDefinition<T> Sortable(Func<T, object?> key);

Sortable by an explicit key (e.g. the raw number behind a formatted amount). Also becomes the default group key.

SortWith

public ColumnDefinition<T> SortWith<TKey>(Comparison<TKey> comparison);

Convenience over the column's KEY TYPE: casts to TKey and delegates — the key comes from ColumnDefinition.Sortable, so the caller knows its type.

SortWith

public ColumnDefinition<T> SortWith(IComparer<object?> comparison);

Custom ordering for this column: the comparer orders the SORT KEYS (ColumnDefinition.Sortable values), not the items, and applies to sorting, grouping and the filter pane alike.

Nulls-first stays with the engine — the comparer only sees non-null pairs. If it throws, it is disabled and reported once; the column then orders by the built-in value order.

For TEXT order instead of value order no comparer is needed: Sortable(z => displayText(z)) says exactly that.

SpeakAs

public ColumnDefinition<T> SpeakAs(Func<T, string> speak);

What a screen reader SPEAKS for this cell, when the visual text is not speakable — a checkmark glyph ("✓") should say "aktiv", a color-only tag its meaning.

This is the developer's half of the narration contract: the GRID owns the scaffolding (position, selection, timing), the APPLICATION owns the content — and by default that content is simply the column's display text, so nothing needs to be done twice. This override exists for the cells where eye and ear diverge.

Style

public ColumnDefinition<T> Style(Func<T, bool> when, Rgba? foreground = default, bool bold = false, Rgba? background = default);

Conditional formatting: when when matches the row, apply the given foreground/weight/background to this cell.

Summable

public ColumnDefinition<T> Summable(Func<T, decimal> value);

Declare the column summable (Σ menu offers all five aggregates) without activating any summary yet.

SummableWith

public ColumnDefinition<T> SummableWith(string label, Func<IReadOnlyList<int>, IItemsSource, decimal> compute, Func<decimal, string>? format = null);

Offer a custom aggregate in the Σ menu without showing it yet.

Summary

public ColumnDefinition<T> Summary(AggregateFn fn, Func<T, decimal>? value = null, Func<decimal, string>? format = null);

Add an aggregate to this column's summaries (Sum/Avg/Min/Max need value; Count does not). Call more than once to stack several. format overrides the displayed text for this column (else the central ArionFormats.Summary default applies).

Summary

public ColumnDefinition<T> Summary(string label, Func<IReadOnlyList<int>, IItemsSource, decimal> compute, Func<decimal, string>? format = null);

Show a CUSTOM aggregate for this column: compute gets the item indexes and the source of the set it summarises (the filtered view for the footer, the group's leaves per group). format defaults to the plain number.

SummaryChoices

public ColumnDefinition<T> SummaryChoices(params AggregateFn[] fns);

Dev override of WHICH aggregates the Σ menu offers for this column (else the default: all five when summable, otherwise none). Use e.g. SummaryChoices(AggregateFn.Count) to offer Count on a text column, or a subset to restrict a numeric one. Value aggregates still need a numeric projection via ColumnDefinition.Summable or ColumnDefinition.Summary.

Validate

public ColumnDefinition<T> Validate(Func<string, string?> validator);

Custom edit validation: input → error text (null = valid).

WithCompositionInset

public ColumnDefinition<T> WithCompositionInset(double inset);

See ColumnDefinition.CompositionInset.

WithDataType

public ColumnDefinition<T> WithDataType(ColumnDataType type);

Declare the column's value kind explicitly (e.g. Date).

WithDateEditor

public ColumnDefinition<T> WithDateEditor(Func<T, DateTime?>? value = null, string? commitFormat = null);

Edit this column with a CALENDAR picker (double-click / F2 opens it; the pick commits through the normal edit path — the column's setter parses the date string). value gives the calendar its initial selection; omit it to parse the display text. Marks the column ColumnDataType.Date unless a type was set explicitly.

WithDateFormat

public ColumnDefinition<T> WithDateFormat(string format);

The exact format the column's text is written and read in, without a calendar: validation, the filter row and date grouping parse it format-first, so a dd.MM.yyyy column stays readable under any UI culture.

WithDropDownButton

public ColumnDefinition<T> WithDropDownButton(DropDownButtonMode mode);

Control when the ▾ dropdown button shows (hover / always / never).

WithEditOptions

public ColumnDefinition<T> WithEditOptions(Func<T, IReadOnlyList<string>> options, DropDownStyle style = default);

Give the editor a fixed choice list (combo picker) instead of free text. Requires an editable setter so the pick can be committed. style picks the look (menu / classic).

WithEditText

public ColumnDefinition<T> WithEditText(Func<T, string> raw);

Give the editor a RAW text projection (see ColumnDefinition.EditText).

WithGrouping

public ColumnDefinition<T> WithGrouping(Func<T, object?>? key = null, Func<object?, string>? label = null);

WithInputMask

public ColumnDefinition<T> WithInputMask(string mask, char promptChar = '_');

Constrain the editor to an input mask (e.g. "00.00.0000" for a date, "(000) 000-0000" for a phone). promptChar is the placeholder shown at unfilled slots — pass ' ' (space) to hide the prompt. See InputMask.

WithKey

public ColumnDefinition<T> WithKey(string key);

WithSelectAllOnEdit

public ColumnDefinition<T> WithSelectAllOnEdit(bool selectAll = true);

Override whether entering edit mode selects this column's whole content (else places the caret) — overrides the grid default.

WithValue

public ColumnDefinition<T> WithValue<TValue>(Func<T, TValue?> get, Func<string, TValue?>? read = null, Func<TValue, decimal>? asNumber = null) where TValue : struct;

Declares which typed VALUE the column carries. The display text stays what the user sees; counting and ordering use this value (otherwise a number column orders lexicographically: "1, 10, 11, 2, ...").

Parameters

read

Parses a search text into this value space — the column knows its culture and format, the filter does not. Without a reader the filter falls back to text comparison.

asNumber

Numeric view of the value — number columns only; the export writes a real numeric cell with it instead of a string.

WithWidth

public ColumnDefinition<T> WithWidth(double width);

WithWrap

public ColumnDefinition<T> WithWrap(int lines = 2);

Let this column's text wrap onto up to lines lines. Pair it with a taller row height — the row does not grow by itself.