refactor!: Align divergent property types with WinUI (sync-gen)#23655
refactor!: Align divergent property types with WinUI (sync-gen)#23655MartinZikmund wants to merge 2 commits into
Conversation
Remove the by-name Content/EasingFunction/ElementName exceptions from the sync generator's property-type matcher (#2086) and align Uno's hand-written types to the WinAppSDK metadata: - DoubleAnimation.EasingFunction: IEasingFunction -> EasingFunctionBase - Binding.ElementName: object -> string; the late-binding subject moves to a new Uno-only ElementNameSubject property (set by the XAML codegen and the runtime reader, read by BindingExpression), mirroring the CompiledSource seam - Content: the exception was stale (every type already matched WinUI) SwipeControl now assigns a null EasingFunction (interpolated linearly by the animator) instead of the non-EasingFunctionBase LinearEase.Instance. Regeneration of the sync-generator output is byte-identical. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WbaZY42v4K7Fp3t2GuHnjc
Binding.ElementName (object -> string) and DoubleAnimation.EasingFunction (IEasingFunction -> EasingFunctionBase) change the public accessor signatures; add the corresponding 6.6-baseline ignore entries (#2086). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WbaZY42v4K7Fp3t2GuHnjc
|
Claude finished @MartinZikmund's task in 4m 56s —— View job Review:
|
| case nameof(Binding.ElementName): | ||
| var subject = new ElementNameSubject(); | ||
| binding.ElementName = subject; | ||
| binding.ElementNameSubject = subject; |
There was a problem hiding this comment.
The Binding.ElementName string property is not set anywhere in this handler, so binding.ElementName will be null after the runtime reader parses {Binding ElementName=Foo}. The subject carries the resolution machinery and the binding works correctly, but reading back binding.ElementName returns null instead of "Foo".
WinUI's contract is that a property you write in XAML is readable back from the binding object. To keep that roundtrip consistent, consider also setting the string after the if check:
if (bindingProperty.Value?.ToString() is { } value)
{
binding.ElementName = value; // keep public string in sync
AddElementName(value, subject);
}This doesn't affect binding resolution (which goes through the subject), but avoids a surprising null for tooling or diagnostic code that inspects binding.ElementName.
There was a problem hiding this comment.
Pull request overview
This PR aligns Uno’s public API surface with WinUI metadata by removing special-case property-type mismatches in the WinAppSDK sync generator and updating the affected Uno types (Binding.ElementName, DoubleAnimation.EasingFunction) plus related XAML/codegen plumbing.
Changes:
- Removed by-name property type “match” exceptions in
Uno.WinAppSDKSyncGeneratorforContent,EasingFunction, andElementName(keeping onlyContentTemplateRootdivergence). - Updated
DoubleAnimation.EasingFunctionto useEasingFunctionBaseand adjusted a consumer (SwipeControl) accordingly. - Split
Binding.ElementNameto a WinUI-paritystringplus Uno-onlyElementNameSubject, and updated XAML reader, binding engine, source generator, and goldens.
Reviewed changes
Copilot reviewed 9 out of 13 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| src/Uno.WinAppSDKSyncGenerator/Helpers/SymbolMatchingHelpers.cs | Removes stale property-type exceptions so sync-gen requires true type matches. |
| src/Uno.UI/UI/Xaml/Media/Animation/DoubleAnimation.cs | Narrows EasingFunction to EasingFunctionBase and updates DP registration. |
| src/Uno.UI/UI/Xaml/Markup/Reader/XamlObjectBuilder.cs | Routes runtime XAML {Binding ElementName=...} through ElementNameSubject. |
| src/Uno.UI/UI/Xaml/DependencyPropertyDetailsCollection.cs | Hot-reload binding cloning now copies ElementNameSubject. |
| src/Uno.UI/UI/Xaml/Data/Binding.cs | Changes ElementName to string and adds Uno-only ElementNameSubject. |
| src/Uno.UI/UI/Xaml/Controls/SwipeControl/SwipeControl.Uno.cs | Uses null easing for linear interpolation when inertia is used. |
| src/Uno.UI/DataBinding/BindingExpression.cs | Switches element-name sourcing logic from ElementName to ElementNameSubject. |
| src/SourceGenerators/Uno.UI.SourceGenerators/XamlGenerator/XamlFileGenerator.cs | Emits ElementNameSubject = ... instead of ElementName = ... in generated bindings. |
| src/SourceGenerators/Uno.UI.SourceGenerators.Tests/**/XamlCodeGenerator_*.cs (4 files) | Updates golden outputs to use ElementNameSubject. |
| build/PackageDiffIgnore.xml | Adds ignore entries for the intentional API signature changes. |
Comments suppressed due to low confidence (1)
src/Uno.UI/UI/Xaml/Markup/Reader/XamlObjectBuilder.cs:1210
- The runtime XAML reader now populates
Binding.ElementNameSubjectbut never assigns the publicBinding.ElementNamestring. This leavesElementNameunset for{Binding ElementName=...}created via the runtime reader, which is inconsistent with the WinUI API surface and makes debugging/introspection harder. Assign the string value in addition to tracking the subject.
case nameof(Binding.ElementName):
var subject = new ElementNameSubject();
binding.ElementNameSubject = subject;
if (bindingProperty.Value?.ToString() is { } value)
{
AddElementName(value, subject);
}
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| /// Gets or sets the name of the element to use as the binding source for the Binding. | ||
| /// </summary> | ||
| /// <value>The name of the element, or an ElementNameSubject instance that can be used to monitor the element name instance changes.</value> | ||
| public object ElementName { get; set; } | ||
| /// <value>The name of the element.</value> | ||
| public string ElementName { get; set; } | ||
|
|
| newBinding.TargetNullValue = binding.TargetNullValue; | ||
| newBinding.ElementName = binding.ElementName; | ||
| newBinding.ElementNameSubject = binding.ElementNameSubject; | ||
| newBinding.FallbackValue = binding.FallbackValue; |
|
🤖 Your WebAssembly Skia Sample App stage site is ready! Visit it here: https://unowasmprstaging.z20.web.core.windows.net/pr-23655/wasm-skia-net9/index.html |
|
The build 220796 did not find any UI Test snapshots differences. |
GitHub Issue: https://github.com/unoplatform/uno-private/issues/2086 (part of #8339)
PR Type:
💬 Other: API alignment for 7.0 (source/binary-breaking, no behavior change)
What changed? 🚀
The WinAppSDK sync generator (
Uno.WinAppSDKSyncGenerator) carried three by-name exceptions in its property-type matcher (SymbolMatchingHelpers.ArePropertiesMatching) that treated a property-type mismatch between the WinAppSDK metadata and Uno's hand-written members as "matching", to avoid a breaking change. For 7.0 (a major) we remove those exceptions so the generated public surface mirrors the WinAppSDK metadata, and align Uno's declared types to match.The three cases (
Content,EasingFunction,ElementName):Content— the exception was stale. Every WinAppSDK type that declares aContentproperty already has a matching Uno type (UIElement↔UIElement,object↔object). Removing theContentclause changes nothing in the generated output; no Uno type change was needed.DoubleAnimation.EasingFunction:IEasingFunction→EasingFunctionBase. WinAppSDK metadata declares this property (and the siblingColorAnimation/PointAnimation/Easing*KeyFrameones) asEasingFunctionBase; theIEasingFunctiontyping was a WPF holdover.EasingFunctionBase : IEasingFunction, so the internalIAnimation<T>contract and the animator pipeline are unaffected.DoubleAnimationwas the only type the exception actually masked —ColorAnimation/PointAnimationhave no hand-written publicEasingFunctionand already emitted the correctEasingFunctionBasestub.SwipeControlassigned the internal, non-EasingFunctionBaseLinearEase.Instanceto the public property. It now assignsnull, which the animator interpolates linearly (_easing = easingFunction ?? LinearEase.Instance) — identical behavior, and closer to WinUI (linear = no easing function).Binding.ElementName:object→string. The WinUI IDL declaresString ElementName. Uno usedobjectto carry either the element-name string or anElementNameSubjectused for late binding. The subject is relocated to a new Uno-only[EditorBrowsable(Never)]Binding.ElementNameSubjectproperty — structurally identical to the existing public Uno-onlyCompiledSourceseam on the same class. It must be public because the compiled-XAML output lives in the consuming assembly (no access to Uno.UI internals). The XAML code generator, the runtime XAML reader,BindingExpression, and the cross-store binding copy all route the subject through the new property.Bindingis the only WinAppSDK type with anElementNameproperty, so no other declaration is affected.The by-name exceptions for these three are removed; only the genuine
ContentTemplateRootdivergence (native-view typed) is kept.Validation
Microsoft.WindowsAppSDK2.1.3). After the type alignments and with all three exceptions removed, the regeneratedGenerated/tree is byte-identical to baseline (emptygit diffon*Generated*, exit 0). This proves the members now match the WinAppSDK metadata with no new[NotImplemented]stubs — the result transfers to CI.Uno.UI.Skia(net10.0) andUno.UI.SourceGeneratorsbuild clean (0 errors). TheSwipeControlconsumer break was caught here and fixed.Uno.UI.SourceGenerators.TestsGiven_Binding+Given_Parserpass; the 4 XAML goldens with{Binding ElementName=…}now emitElementNameSubject = _…Subject(updated in this PR).Given_Control.When_Refresh_Setter_BindingOnInvocation_ElementNameandGiven_ListViewBase.When_Outer_ElementName_Binding— both pass (2/2), confirming theElementNameSubjectrelocation resolves{Binding ElementName=…}end-to-end.Given_DoubleAnimation.When_EasingFunctionis#if __ANDROID__-gated (native-Android-only assertion) and does not run on Skia; theEasingFunctionBasenarrowing is behavior-identical (a null easing is still interpolated linearly) and compile-validated.PR Checklist ✅
Screenshots Compare Test Runresults (N/A — no visual change)Breaking change impact
Binding.ElementNamechanges fromobjecttostring(source + binary break). Code-behind assigning a subject toElementNameno longer compiles (undocumented Uno-internal pattern); assigning a string still compiles and matches WinUI. Precompiled third-party XAML libraries using{Binding ElementName=…}generated against an older Uno.UI must be recompiled — appropriate within the 7.0 breaking-changes window.DoubleAnimation.EasingFunctionchanges fromIEasingFunctiontoEasingFunctionBase(source + binary break). Callers assigning a customIEasingFunctionthat does not derive fromEasingFunctionBaseno longer compile — this matches WinUI, whereEasingFunctionBaseis the only valid public value.Binding.ElementNameSubjectproperty is added ([EditorBrowsable(Never)], Uno-only); it is ignored by the sync generator (WinUI has no such member).