This document captures design and implementation notes for the validation infrastructure.
For end-user usage and examples, see Validation.
ValidationSeverityThree severities:
InfoWarningErrorSeverity affects the glyph, the message text style, and the default foreground color.
ValidationPlacementControls where the message is placed relative to the wrapped content:
AboveBelow (default)ValidationMessageValidationMessage is a small value type:
ValidationSeverity SeverityVisual ContentThe message content is a Visual to allow rich composition (text, markup, links, layout containers).
ValidationPresenterValidationPresenter : ContentVisual wraps a single Content visual and optionally shows a message.
Bindable properties:
ValidationMessage? MessageValidationPlacement PlacementValidationPresenter is not focusable (Focusable = false). The wrapped Content keeps its own input behavior.
ValidationExtensionsConvenience methods in ValidationExtensions make the feature easy to use without explicit presenter construction:
content.Validation(ValidationMessage?)content.Validation(Binding<ValidationMessage?>)content.Validation(State<ValidationMessage?>)content.Validate(valueBinding, validator, placement)Validate(...) binds ValidationPresenter.Message to a computed binding that calls the validator on demand:
null when valid.ValidationPresenter always has a ValidationMessageHost child attached, even when no message is displayed. The host collapses itself to Size.Zero when Message is null.
This keeps style inheritance stable and avoids frequent attach/detach of the host itself.
ValidationPresenter.MeasureCore:
Content (if any) with the incoming constraints.contentHeight + messageHeight + Gap, where Gap comes from ValidationStyle and is only applied when a message is present.SizeHints.Flex(...) and normalizes the result.ValidationPresenter.ArrangeCore:
FlexAllocator.Allocate to distribute height between content and message based on their min/natural/max hints.ValidationStyle.Gap between content and message only when a message is present.Placement:
Above: message first, then content.Below: content first, then message.ValidationPresenter maintains a cached _resolvedMessage and calls EnsureMessageApplied() during layout.
This exists for a binding-system detail:
Message is updated through a generated binding (including two-way bindings), updates may bypass the C# property setter.ValidationPresenter must still detect the new value so it can update the internal host (attach/detach the message content and re-measure/re-arrange it).EnsureMessageApplied() actively reads Message during layout and pushes it to the host when it changes. This ensures message changes participate in dependency tracking and invalidation.
Validation is styled by ValidationStyle:
Padding: padding around the entire line/block.GlyphSpacing: number of spaces after the severity glyph.Gap: vertical spacing between the wrapped content and the message.InfoGlyph, WarningGlyph, ErrorGlyph: optional glyphs (nullable Rune).
U+2139 (info), U+26A0 (warning), U+26D4 (error).InfoStyle, WarningStyle, ErrorStyle: optional style overrides for the message line.If no override style is provided, the line foreground is derived from the theme:
Theme.Muted (or fallback Theme.Foreground)Theme.Warning (or fallback Theme.Foreground)Theme.Error (or fallback Theme.Foreground)ValidationMessageHost rendering detailsValidationMessageHost is an internal Visual that implements the line/block rendering:
PrepareChildren, it attaches/detaches the message Content visual based on Message.TextBlock or Markup, it sets Wrap(true) so messages wrap by default.MeasureCore, it subtracts Padding and the prefix width (glyph + spacing) from the available width before measuring the message content.ArrangeCore, it offsets the message content rectangle by Padding.Left and prefix width.RenderOverride, it fills the entire host bounds with spaces using the resolved line style, then writes the prefix at the top-left (after padding).StyleEnvironment[TextBlockStyle.Key] to a severity-appropriate TextBlockStyle so TextBlock children inherit the correct foreground by default.ValidationPresenter and ValidationMessageHost are not focusable.Link), those visuals can still participate in hit testing normally.src/XenoAtom.Terminal.UI.Tests/ValidationPresenterTests.cs verifies that Validate(...) reevaluates the validator when the bound value changes.samples/ControlsDemo/Demos/ValidationDemo.cs shows "below" vs "above" placement and a custom ValidationStyle.NumberBox<T> composes ValidationMessageHost directly to surface parse/validation errors without requiring external wrappers.