Skip to content

Field

Field folds the web family’s Field/FieldLabel/FieldControl/FieldDescription/FieldItem/FieldError/ FieldValidity/Input anatomy into one push-based coordinator. Instead of cascading a FieldContext object for descendants to pull (WPF has no cascading-parameter mechanism), NaviusField walks its logical tree once its Content is assigned, registers the descendant control (default-filling an empty NaviusFieldControl with a NaviusInput), wires the label’s Target, and pushes fresh validity into every NaviusFieldError. The web’s discrete state attributes become read-only dependency properties computed from WPF’s own bubbling Validation.Error, TextChanged, and GotFocus/LostFocus events instead of a ported JS constraint-validation bridge.

xmlns:field="clr-namespace:Navius.Wpf.Primitives.Controls.Field;assembly=Navius.Wpf.Primitives"
<field:NaviusField FieldName="email" ValidationMode="OnBlur">
<StackPanel>
<field:NaviusFieldLabel Content="Email" />
<field:NaviusFieldControl>
<field:NaviusInput Text="{Binding Email, ValidatesOnNotifyDataErrors=True}" />
</field:NaviusFieldControl>
<field:NaviusFieldDescription Content="We only use this to send receipts." />
<field:NaviusFieldError />
</StackPanel>
</field:NaviusField>
Property Type Default From Description
FieldName string "" NaviusField Form-field name key, matched against NaviusForm.Errors. Renamed from the web’s Name to avoid hiding FrameworkElement.Name, which x:Name/FindName rely on.
Disabled bool false NaviusField Drives IsEnabled; combined with an enclosing NaviusFieldset’s own disabled cascade via native IsEnabled tree inheritance.
Invalid bool false NaviusField Consumer “mark invalid” flag. Does not auto-clear.
ServerInvalid bool false NaviusField Server-side invalidity. Auto-clears on the next descendant TextChanged.
ValidationMode FieldValidationMode OnSubmit NaviusField OnSubmit / OnBlur / OnChange; gates when IsFieldValid/IsFieldInvalid are revealed.
ExternalErrors IReadOnlyList<string>? null NaviusField Error messages injected by name, typically by NaviusForm.Errors.
IsFieldValid bool? null NaviusField Read-only. Tri-state: null until Reveal()’d, matching the web’s valid: null.
IsFieldInvalid bool false NaviusField Read-only.
IsDirty bool false NaviusField Read-only. Set on the first descendant TextChanged.
IsTouched bool false NaviusField Read-only. Set on the first descendant LostFocus.
IsFilled bool false NaviusField Read-only. True when the registered TextBox’s Text is non-empty.
IsFieldFocused bool false NaviusField Read-only. Tracks descendant GotFocus/LostFocus.
RegisteredControl UIElement? null NaviusField CLR property (not a DP): the descendant control found or default-filled by WireDescendants.
Content object - ContentControl (NaviusFieldControl) Hosts the field-aware control; NaviusField default-fills a NaviusInput when left empty and registers whatever ends up here.
Target FrameworkElement null Label (NaviusFieldLabel) Wired by the ancestor NaviusField to the registered control; gives native Alt+mnemonic focus, plus an explicit PreviewMouseLeftButtonDown handler for plain-click delegation (WPF’s Label does not focus Target on a non-mnemonic click by itself).
Content object - ContentControl (NaviusFieldDescription) Supplementary field text; NaviusField reads its string Content and applies it as AutomationProperties.HelpText on the registered control.
Content object - ContentControl (NaviusFieldItem) Groups one item’s label + description (e.g. inside a checkbox/radio list); no field-state wiring of its own.
Match string? null NaviusFieldError Narrows display to a specific error message string (not an HTML5 validity key); null shows whenever the field is invalid.
ForceMatch bool false NaviusFieldError Shows unconditionally regardless of validity.
Content object null ContentControl (NaviusFieldError) Custom error content; when null and shown, defaults to the joined error messages.
Text string "" TextBox (NaviusInput) Inherited from TextBox; natively two-way bindable, no separate Value/DefaultValue pair is needed.
Method Description
Reveal() Surfaces current validity per ValidationMode. Called by NaviusForm on every submit attempt (the stand-in for the web’s FieldContext.RevealAsync()); a consumer can also call it directly outside a Form.
RegisterControl(UIElement) Registers an arbitrary descendant as the field’s control (used internally by WireDescendants).
FocusRegisteredControl() Focuses RegisteredControl; called by NaviusForm to focus the first invalid field.

NaviusField ships no custom AutomationPeer. Accessible-name association happens on the registered control, not the field wrapper: NaviusFieldLabel.Target gives native Label→control wiring, and AutomationProperties.HelpText is applied to the registered control from the first NaviusFieldDescription descendant’s string content (fixed in the M6 audit; previously missing entirely). NaviusFieldError carries AutomationProperties.LiveSetting=Assertive, the UIA analog of role="alert". The discrete state DPs (IsDirty/IsTouched/IsFilled/IsFieldFocused/ IsFieldValid/IsFieldInvalid) are computed from real bubbling WPF events rather than surfaced attributes. The unit suite exercises this against real windows, including the M6 regression FieldTests.FieldDescription_IsAssociatedWithControl_ViaAutomationHelpText.

  • No cascading-parameter equivalent exists in WPF: NaviusField pushes to descendants on OnContentChanged instead of parts pulling a cascaded FieldContext, deliberately avoiding FrameworkElement.Loaded, which never fires outside a live Window.
  • The web’s GUID id registry (ControlId, DescribedBy, message ordering) is dropped entirely: label/description association uses element references (Label.Target, AutomationProperties.HelpText) instead of for=/aria-describedby ids.
  • FieldValidity’s HTML5 ValidityState flag set (BadInput/PatternMismatch/StepMismatch/…) collapses to a single invalid/valid plus message-list model read off WPF’s own Validation.GetErrors, so NaviusFieldError.Match matches a message string, not a validity key.
  • Name became FieldName (FrameworkElement.Name is load-bearing for x:Name/FindName).
  • ServerInvalid auto-clears only on a descendant TextChanged: what counts as “the next edit” for non-text controls (ComboBox, DatePicker, CheckBox) stays unresolved, the same open question the web contract itself leaves open.
  • The ControlProps/@attributes splat pattern (NaviusFieldControl.ChildContent cascading a custom control’s wiring) is replaced by WPF’s ordinary Content model: any control placed inside NaviusFieldControl gets registered, nothing needs to be splatted.
  • NaviusFieldValidity (a render-prop exposing the live validity snapshot) has no separate control: consumers bind directly to the public read-only DPs instead.
  • Known residual (M6 audit): the label-to-control accessible-name relationship relies solely on native Label.Target, not an explicit AutomationProperties.LabeledBy the way NaviusFieldset wires it for its legend; this was not independently verified with a screen reader or UIA client.
  • Known residual (M6 audit): the error message is surfaced only as an assertive live region, not also mirrored into the control’s HelpText, so a screen reader that reads describedby/help on focus rather than the live announcement would not hear the current error. Parity of announcement with the web’s aria-describedby error ids was not verified with assistive technology.

The Field Gallery page rendered at the pinned commit, in each theme.

Field Gallery page in the light theme

Field Gallery page in the dark theme

Field Gallery page in the high contrast theme