Form
Overview
Section titled “Overview”Form is a lookless ContentControl scope root: on submit it clears injected errors, raises
ClearErrorsRequested, re-applies its Errors dictionary, reveals every descendant NaviusField,
and then either raises Submitted (every field valid) or focuses the first invalid field. There is
no ported FormContext register/unregister registry: every orchestration point does a fresh
logical-tree walk for descendant NaviusFields, which is always correct and needs no lifecycle
management.
xmlns:form="clr-namespace:Navius.Wpf.Primitives.Controls.Form;assembly=Navius.Wpf.Primitives"xmlns:field="clr-namespace:Navius.Wpf.Primitives.Controls.Field;assembly=Navius.Wpf.Primitives"
<form:NaviusForm x:Name="SignupForm" Errors="{Binding ServerErrors}"> <StackPanel> <field:NaviusField FieldName="email"> <!-- label / control / description / error --> </field:NaviusField> <form:NaviusFormSubmit Content="Create account" IsDefault="True" /> </StackPanel></form:NaviusForm>Properties
Section titled “Properties”| Property | Type | Default | From | Description |
|---|---|---|---|---|
Errors |
IReadOnlyDictionary<string, string[]>? |
null |
NaviusForm |
Validation errors keyed by FieldName; pushed into each matching field’s ExternalErrors on change and cleared from non-matching fields. |
Command |
ICommand |
null |
Button (NaviusFormSubmit) |
Auto-wired to the ancestor form’s SubmitCommand on Loaded, unless the consumer already bound one. |
Commands
Section titled “Commands”| Command | Description |
|---|---|
SubmitCommand |
Read-only per-instance ICommand property (not a static RoutedCommand). Bind a Button.Command to it, or use NaviusFormSubmit, which auto-wires it. Executing it clears injected errors, raises ClearErrorsRequested, re-applies Errors, reveals every descendant field, then raises Submitted or focuses the first invalid field. CanExecute always returns true; validity is enforced inside the command body, not via CanExecute/IsEnabled. |
Methods
Section titled “Methods”| Method | Description |
|---|---|
Reset() |
Raises ClearErrorsRequested and clears every descendant field’s ExternalErrors. |
Events
Section titled “Events”| Event | Signature | Fires when |
|---|---|---|
Submitted |
RoutedEventHandler |
From HandleSubmit, only when every descendant NaviusField is valid after Reveal(). |
ClearErrorsRequested |
RoutedEventHandler |
At the start of a submit attempt (before revalidating), and again on Reset(). |
Keyboard interactions
Section titled “Keyboard interactions”| Key | Behavior |
|---|---|
Enter (inside any control, when a NaviusFormSubmit with IsDefault="True" is in scope) |
Triggers the default button’s Command (the form’s SubmitCommand) via the native WPF Button.IsDefault mechanism; not custom-coded by this family. |
UIA mechanism
Section titled “UIA mechanism”Neither NaviusForm nor NaviusFormSubmit overrides OnCreateAutomationPeer: NaviusForm ships
no custom peer, and NaviusFormSubmit inherits the native ButtonAutomationPeer
(AutomationControlType.Button with InvokePattern), unchanged. No role= or aria-* wiring is
asserted in the web contract either. On a blocked submit, focus moves to the first invalid field
via NaviusField.FocusRegisteredControl(), a direct element reference replacing the web’s
JS-interop focusElementById fallback. The unit suite drives NaviusForm.SubmitCommand.Execute(null)
directly against a real Validation-bound field tree (FormTests.cs).
Web deltas
Section titled “Web deltas”FormContext’s register/unregister field registry is not ported:NaviusFormre-walks its own logical tree (LogicalTreeWalker.Descendants<NaviusField>) at each submit/reset, always correct with no lifecycle bookkeeping.PreventDefaultis dropped, not stubbed: there is no browser-level default submit navigation to prevent in WPF.FormData(the name-to-value snapshot exposed to a customMatchFn) is not ported: WPF consumers read values from their own bound view models directly.- The JS
focusElementByIdfallback used when a field has noFocusControlis gone: focus always goes through a directUIElementreference (NaviusField.FocusRegisteredControl), silently no-op if a field has no registered control. OnClearErrorsstays argument-less (ClearErrorsRequestedis a plainRoutedEventArgs); no richer signature was added.- Enter-to-submit is the native WPF idiom (
Button.IsDefault) rather than an emulated implicit<form>behavior. - Known residual (M6 audit):
NaviusFormSubmit’s auto-wire ofCommandto the ancestor form’sSubmitCommandruns inside aLoadedhandler, which never fires for elements outside a live Window; this path is untested by the headless unit suite (which drivesSubmitCommand.Execute(null)directly) and is expected, but not verified, to work in a real window. - Known residual (M6 audit):
SubmitCommand.CanExecutealways returnstrueandCanExecuteChangedis a no-op, so the original strategy note’s idea of a submit button tracking form validity viaCanExecute/IsEnabledwas not implemented; validity is enforced inside the command body instead. Consistent with the port’s explicit-command model, but not flagged as a delta in the original implementation notes.
Captures
Section titled “Captures”The Form Gallery page rendered at the pinned commit, in each theme.


