Conversation
WinAppSDK sync generator drift detected on
|
|
🤖 Your Docs stage site is ready! Visit it here: https://unodocsprstaging.z13.web.core.windows.net/pr-24838/docs/index.html |
|
🤖 Your WebAssembly Skia Sample App stage site is ready! Visit it here: https://unowasmprstaging.z20.web.core.windows.net/pr-24838/wasm-skia-net9/index.html |
There was a problem hiding this comment.
make sure DefaultCompactErrorIconTemplate is documented, not just in specs
|
The build 236518 found UI Test snapshots differences: Details
|
92c127f to
80a2860
Compare
There was a problem hiding this comment.
move back properties into attached-DPs (housed under uno.extras, with winappsdk impl being inert)
|
🤖 Your WebAssembly Skia Sample App stage site is ready! Visit it here: https://unowasmprstaging.z20.web.core.windows.net/pr-24838/wasm-skia-net9/index.html |
|
🤖 Your Docs stage site is ready! Visit it here: https://unodocsprstaging.z13.web.core.windows.net/pr-24838/docs/index.html |
|
The build 236733 found UI Test snapshots differences: Details
|
|
🤖 Your Docs stage site is ready! Visit it here: https://unodocsprstaging.z13.web.core.windows.net/pr-24838/docs/index.html |
|
🤖 Your WebAssembly Skia Sample App stage site is ready! Visit it here: https://unowasmprstaging.z20.web.core.windows.net/pr-24838/wasm-skia-net9/index.html |
|
The build 236770 found UI Test snapshots differences: Details
|
|
🤖 Your WebAssembly Skia Sample App stage site is ready! Visit it here: https://unowasmprstaging.z20.web.core.windows.net/pr-24838/wasm-skia-net9/index.html |
|
The build 237007 found UI Test snapshots differences: Details
|
|
🤖 Your Docs stage site is ready! Visit it here: https://unodocsprstaging.z13.web.core.windows.net/pr-24838/docs/index.html |
|
|
Records the input-validation design as two staged specs. Docs only, no production code changes. Neither WinUI nor Uno has an input-validation story (microsoft-ui-xaml#179 open since 2019, its spec PR unmerged, #4839 closed as blocked/missing-api). INotifyDataErrorInfo already works on Uno, the binding engine already exposes a binding's leaf source, and {Binding} and {x:Bind} already converge on one funnel -- what is missing is the wiring between them plus a bindable read model. specs/059-input-validation (Proposal) covers the transport layer and the read model: participation decided at DependencyPropertyDetailsCollection.SetBinding where both SetBindingInternal overloads converge (and where ResourceBinding is structurally excluded), resolution through BindingExpression.OnValueChanged against the binding's leaf, the validation property declared by a new Uno InputValidationPropertyAttribute on the control type and cached under a new FeatureConfiguration.InputValidation, and the Validation.IsEnabled/HasErrors/Errors attached properties plus a public IInputValidationControl. WinUI's InputPropertyAttribute is deliberately not reused and not honoured as a fallback: it means XAML child-element processing, not "the property the user types into", and ComboBox already carries it for that meaning. The new attribute is AllowMultiple = false for now -- an editable ComboBox validating both Text and SelectedItem is the case that would trigger a revisit, and widening it later stays source- and binary-compatible, provided resolution stops relying on GetCustomAttribute (which throws AmbiguousMatchException once multiple are allowed). Inherited = true, so a third-party MyTextBox : TextBox participates unchanged, under the convention that the attribute never sits on a shared base with non-validating subclasses. A FrameworkPropertyMetadataOptions flag was considered and rejected: a DependencyProperty is registered once per inheritance branch and Uno has no OverrideMetadata, so a per-DP flag cannot separate Slider from ProgressBar nor ComboBox from FlipView. A type-level attribute resolves per type, and works because InternalGetProperty walks the base-type chain. specs/060-input-validation-presentation (Deferred) covers the built-in visuals, and records two blocking findings rather than leaving them to be rediscovered: Control.ChangeVisualState is private protected and 19 of its 31 overrides skip the base call (including every control that would participate), and ValidationStates cannot be given priority over CommonStates because both write through a single animated-value slot that records no writer. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
DependencyPropertyDescriptor.Parse redirects a parenthesized binding path to the
attached property's owner type, but only the originally queried type's static
constructor had been forced. When the owner had not been initialized yet its
property was not registered, the lookup missed, and the null was negatively
cached -- so a binding to an attached path read the initial value once and never
subscribed to changes. Affects any `{Binding (Owner.Property)}`, Canvas.Left
included.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Implements steps 1-3 of specs/059-input-validation: - ValidationPropertyAttribute declares which dependency property of a control type is its input, resolved through the existing DependencyProperty.GetProperty and cached per type (negative answers included) in a ConditionalWeakTable, so the cache does not pin collectible AssemblyLoadContexts. - FeatureConfiguration.Validation hosts the app-wide switch and that lookup. - Validation exposes IsEnabled / HasErrors / Errors as attached properties, the read model an application binds its own error markup to. Inert until the transport layer populates them. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Implements step 4 of specs/059-input-validation. Participation is decided where both SetBindingInternal overloads converge, which is also the only place the owner and the fresh BindingExpression are both in hand; a ResourceBinding never reaches it. Resolution is separate and runs on BindingExpression.OnValueChanged, the funnel every path re-resolution passes through -- including the initial one, which is what survives a source whose value already equals the target property default. The subscription is keyed on the control rather than on the expression, since a rebound property replaces its expression with no notification. ErrorsChanged is subscribed weakly so a view model cannot root the control, and an off-thread raise hops to the dispatcher. Two hazards the spec did not cover are handled here: the attached property is usually set after the binding in generated XAML, so registration cannot be gated on it and the changed callback pulls the current expression instead; and binding removal is silent, so teardown hooks ClearBinding, which covers both rebinding and ClearValue. Leaf resolution reads the update sources of a compiled binding, not just the binding path -- the latter stays empty for x:Bind, which would otherwise have reproduced microsoft-ui-xaml#4642 in reverse. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Implements step 5 of specs/059-input-validation. TextBox, PasswordBox, NumberBox, AutoSuggestBox, ToggleSwitch, ToggleButton (and so CheckBox and RadioButton), Slider and ComboBox declare their input and re-broadcast the errors of their source. RichEditBox is left out: its content is an ITextDocument with no dependency property to bind. The attribute sits on the leaf type, never on RangeBase or Selector, which is what keeps ProgressBar and FlipView out -- the case a per-dependency-property flag could not have expressed. ErrorChanged is backed by one shared attached property rather than per-control storage, kept apart from the subscription state so handlers survive a rebind. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Shows the whole opt-in: a view model implementing INotifyDataErrorInfo, one attached property on the control, and the error text rendered by the markup of the application through its own converters -- this slice ships none. Enables the feature in SamplesApp startup, which is also where a real application would set it, and covers the compiled-binding path with a unit test. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The spec renames the FeatureConfiguration class and the attribute to carry an InputValidation prefix, so that they no longer read as one type in two places next to the Validation attached-property owner. Also records in the spec what implementation corrected about it: the three lifecycle hazards that do not hold, the compiled-binding leaf, the attached property lookup bug that had to be fixed first, and the resolutions of Q1, Q3, Q5, Q8, Q9 and Q11. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The weakly subscribed ErrorsChanged handler is the part of the design most likely to regress silently, and a strong handler would let one long-lived view model root every control bound to it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Uno.UI.Tests.ViewLibrary is deliberately absent from Uno.UI's InternalsVisibleTo list and is already project-referenced by the unit tests, so a participating control there makes the third-party contract a compile-time one: if any member of the participation surface goes back to internal, the build stops. That is a stronger and far cheaper signal than the throwaway canary head this repo has tried before, which rotted as soon as nobody ran it. MyValidatingControl covers the attribute route; MyMappedValidatingControl covers the escape hatch for a control that cannot carry one, registered through FeatureConfiguration.InputValidation.ValidationProperties. Writing it surfaced a sharp edge worth knowing: FrameworkPropertyMetadata's (value, callback) overload is internal, so such a control registers with PropertyMetadata instead. Given_Validation_ThirdParty then covers what was silently broken before the members became protected -- ValidationError per error added and removed, ErrorChanged carrying the source's args, HasValidationErrors- Changed once per transition rather than per synchronization, and mode changes re-syncing a source that already had errors. Kept the in-assembly doubles rather than moving them out, so the 36 transport tests are untouched; their comment claiming they stand in for a third-party control was the false part, and now points here instead. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Asserts the ten members are protected rather than internal, so an accidental narrowing fails with a named member instead of a compile error from another project. It proves the modifier, not the sufficiency of the surface: a member left internal elsewhere would keep this green while a third-party control still could not be written. The proof of sufficiency is that Uno.UI.Tests.ViewLibrary compiles at all, so do not delete the control there believing this covers it. The names are spelled out rather than taken from nameof, since a protected member is not accessible to a type that does not derive from Control -- which is the point of the guard. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
059 kept describing a Validation class that no longer exists. Section 4.1 gets a superseded banner rather than a rewrite -- 10b's decisions are written against it, so deleting it would strand them -- and 10b gains D3 for the fold onto Control, including the third-party defect the old shape hid and the internal FrameworkPropertyMetadata overload found while proving it fixed. The owner-type, ordering and read-only notes named members that were renamed or removed. 060 claimed three framework triggers where two of them were the same callback, and still placed the shared statics on Validation and ErrorTemplate on an attached property. The historical sections of both specs keep their original wording: 10b is the mechanism that supersedes them, as it already was. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
UpdateValidationStatesInternal now applies or leaves the validation state groups, so OnValidationModeChanged no longer branches on participation only for UpdateValidationStates to re-test it. The template-application hook in FrameworkElement therefore leaves the groups too, closing the mirror of the timing gap it was added for: a control whose mode went to Disabled before its template was realized had its GoToState return false with nothing left to re-apply it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The ObservableValidator of the MVVM Toolkit reports ValidationResult rather than strings, and only its ToString reaches InputValidationError.
Realize the template's ErrorPresenter on the first error and present the ErrorTemplate in it (inline, or in the DefaultCompactErrorIconTemplate tooltip). Wired to HasValidationErrors, InputValidationMode and a new protected OnErrorTemplateChanged, plus template application (Uno-only). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Template realization applies the disabled branch of EnsureValidationVisuals, so a non-participating control lands in ValidationDisabled while its error group stays unset. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Only TextBox, PasswordBox, AutoSuggestBox and ComboBox take part in input validation, as in WinUI's CControl type switches. NumberBox, Slider, ToggleSwitch and ToggleButton no longer implement IInputValidationControl, and ComboBox validates Text rather than SelectedItem, matching its WinUI [InputProperty]. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A non-editable ComboBox is bound on SelectedItem, so validating Text left the common setup without errors. ComboBox validates SelectedItem again; the app-wide map and a shadowing subclass remain the routes to validate SelectedIndex or another property instead. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The boxing analyzer (UnoInternal0002) that landed on master flags the default(bool) metadata of the four per-control HasValidationErrors registrations. Use BoolBoxes.False, as the rest of Uno.UI does. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The WinAppSDK sync generator keeps a placeholder for a hand-implemented type, with its members skipped, and fails the check when it is missing. This is the file it regenerates. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
WinAppSDK exposes no public input validation surface: neither InputValidationError nor TextBox.InputValidationMode exist there, so the sample cannot compile against it. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The handlers and the subscription lived in attached dependency properties, a leftover from when a separate Validation class owned them. A single lazily-created state object on Control now holds them. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The validation surface no longer lives on the WinUI types. The Mode, Kind, ErrorTemplate, HasErrors and Errors properties are now attached properties on Uno.Extras.Input.Validation, in Uno.UI.Extras. On WinAppSDK their handlers are compiled out. - IInputValidationControl is deleted, along with the per-control DPs and the HasValidationErrorsChanged, ValidationError and ErrorChanged events. The HasValidationErrorsChangedEventArgs stub is restored. - InputValidationMode, InputValidationKind and InputValidationError move to Uno.Extras.Input and are compile-linked into Uno.UI.Extras.Windows. - The engine stays on Control. It reads the attached DPs through an internal slot that Validation's static constructor fills, and a control participates through its validation property alone. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
1630679 to
8b8ebbd
Compare
|
🤖 Your WebAssembly Skia Sample App stage site is ready! Visit it here: https://unowasmprstaging.z20.web.core.windows.net/pr-24838/wasm-skia-net9/index.html |
|
🤖 Your Docs stage site is ready! Visit it here: https://unodocsprstaging.z13.web.core.windows.net/pr-24838/docs/index.html |
|
The build 237533 found UI Test snapshots differences: Details
|
|
🤖 Your Docs stage site is ready! Visit it here: https://unodocsprstaging.z13.web.core.windows.net/pr-24838/docs/index.html |
|
🤖 Your WebAssembly Skia Sample App stage site is ready! Visit it here: https://unowasmprstaging.z20.web.core.windows.net/pr-24838/wasm-skia-net9/index.html |
|
The build 237558 found UI Test snapshots differences: Details
|
GitHub Issue: closes #4839, related: unoplatform/uno-private#2384
PR Type:
✨ Feature
What changed? 🚀
Before: Neither WinUI nor Uno supports input validation.
INotifyDataErrorInfoworks in the BCL, but nothing carries its errors from a binding source to the bound control. Apps have to build the whole presentation layer themselves.After: Controls can opt in to WinUI-shaped input validation. Errors from an
INotifyDataErrorInfosource reach the bound control'sHasValidationErrors/ValidationErrorsand drive WinUI's validation visual states and error presenter. Design and rationale are inspecs/059-input-validation/spec.md(transport + read model) andspecs/060-input-validation-presentation/spec.md(visuals). §10/§10b of 059 record where the implementation departed from the original draft.Opt-in (off by default)
Validation is off unless both switches are set. With the global flag off, the binding registration path does no extra work.
InputValidationModedefaults toDisabledrather than WinUI'sAuto, because here it also gates theINotifyDataErrorInfosubscription.Transport
SetBindingInternaloverloads converge. Resolution runs onBindingExpression.OnValueChanged, which both{Binding}and{x:Bind}go through. The leaf source is read from the compiled binding's update sources as well as the binding path, so the two binding kinds behave the same (avoiding microsoft-ui-xaml#4642).ErrorsChangedis subscribed weakly, so a view model cannot keep a control alive. A raise from another thread is dispatched to the UI thread. Teardown hooksClearBinding, which covers rebinding andClearValue.Control(Control.Validation*.cs), where WinUI keeps the equivalent (CControl::IsValidationEnabled/EnsureValidationVisuals).Public surface
Microsoft.UI.Xaml.Controls:IInputValidationControl(WinUI's full interface exceptValidationContext),InputValidationMode,InputValidationKind,InputValidationError,InputValidationErrorEventArgs,InputValidationErrorEventAction,InputValidationContext.HasValidationErrorsChangedEventArgsreplaces its[Uno.NotImplemented]generated stub with a real implementation.Uno.UI.Xaml.Controls:InputValidationPropertyAttributeandInputValidationPropertyMap, which declare which property of a control carries its input.FeatureConfiguration.InputValidation(IsEnabled,ValidationProperties).Controlgains protected helpers (UpdateValidationStates, the changed callbacks, event add/remove helpers,GetOrCreateValidationErrors) so that a control outside Uno.UI can take part.Uno.UI.Tests.ViewLibrary(not covered byInternalsVisibleTo) contains such a control, so the build fails if that contract regresses.PrivateApiContract/Feature_InputValidationIDL, which has never shipped publicly. If microsoft-ui-xaml#179 ships with a different shape, the names will collide. Details in spec 059 §10b.Participants
The participants are WinUI's four:
TextBox→Text,PasswordBox→Password,AutoSuggestBox→Text,ComboBox→SelectedItem.ComboBoxdeparts from WinUI, which validatesText: a non-editableComboBoxis bound onSelectedItem, so validatingTextwould leave the common case with no errors. Each registers its ownInputValidationMode,InputValidationKind,HasValidationErrors,ValidationErrorsandErrorTemplatedependency properties, so aStyleSettercan target them and aBindingcan drive them.Presentation (spec 060, partial)
InputValidationEnabledStates/InputValidationErrorStatesare driven from each participant's visual-state method.CControl::EnsureErrors/DeferErrors: the first error realizes the template'sErrorPresenter, which showsErrorTemplateinline, or in the newDefaultCompactErrorIconTemplatetooltip for compact mode.CommonStatescontention (060 §3 / Q10). The shipped Fluent templates don't have validation parts yet, so nothing appears on screen unless the app's template or markup renders it.Related fix
fix: Resolve attached properties of uninitialized owners(3241cea):DependencyPropertyDescriptor.Parseredirected a parenthesized path to the owner type without running that type's static constructor. The lookup missed and the miss was cached, so{Binding (Owner.Property)}read the initial value once and never updated. This affectedCanvas.Lefttoo.Tests & sample
Uno.UI.UnitTests/InputValidation/): transport, per-control properties, public surface guard, a third-party control, and attached-path resolution.Uno_UI_Xaml_Controls/InputValidation/): validation visual states and the error presenter.Uno/UI/Xaml/Controls/Validation/InputValidation. The SamplesApp now turns the global flag on.PR Checklist ✅
doc/articlespage will follow once the templates (060 §4) landScreenshots Compare Test Runresults.feat!commits only break API added earlier in this branch, which has never been released. Compared withmaster, the changes are additive and off by default.🤖 Generated with Claude Code