refactor!: Remove legacy FeatureConfiguration flags (7.0)#23666
Merged
MartinZikmund merged 13 commits intoJul 7, 2026
Merged
Conversation
The legacy Binding.IgnoreINPCSameReferences flag defaulted to false on all targets and was never assigned by the framework, so the binding engine always took the correct INPC path. Delete the flag (and its now empty FeatureConfiguration.Binding holder) and inline the always-false branch at the three consumer sites in BindingPath.BindingItem.cs. Source-breaking for consumers reading/assigning the flag; no runtime behaviour change. Package-diff entries added for the removed public API. Part of #2053 (remove legacy feature flags, 7.0 breaking changes). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The legacy FrameworkElement.UseLegacyHitTest flag defaulted to false on all targets and was never assigned by the framework, so IsViewHit() always returned false (the WinUI-aligned behavior). Delete the flag and collapse FrameworkElement.IsViewHit() to `=> false`. Source-breaking for consumers reading/assigning the flag; no runtime behaviour change. Package-diff entries added for the removed public API. Part of #2053 (remove legacy feature flags, 7.0 breaking changes). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
UIElement.ShowClippingBounds was an orphaned diagnostic flag with zero consumers anywhere in the tree (the iOS-only visualization it once gated is gone). Delete the flag; setting it was already a no-op. Source-breaking for consumers reading/assigning the flag; no runtime behaviour change. Package-diff entries added for the removed public API. Part of #2053 (remove legacy feature flags, 7.0 breaking changes). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The flag was already get-only (compile-time constant true), so the animation engine always defaulted the starting value from the animated value via GetValueCore(). Delete the flag (and its now-empty FeatureConfiguration.Timeline holder), inline GetValueCore(), and drop the dead private GetNonAnimatedValue wrapper whose only caller was the removed legacy branch. The protected Timeline.GetNonAnimatedValue base method is kept (subclass-facing surface). Source-breaking for consumers reading the flag; no runtime behaviour change. Package-diff entries added for the removed public API. Part of #2053 (remove legacy feature flags, 7.0 breaking changes). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The flag defaulted to false on all targets and was never assigned by the framework, so VisualStateGroup always applied setters at the WinUI-correct time (after the transition). Delete the flag (and its now-empty FeatureConfiguration.VisualState holder), remove the dead early-apply branch, and make the post-transition ApplyTargetStateSetters() call unconditional. The compatibility-mode runtime test that flipped the flag to true and asserted the legacy ordering is deleted (it exercised removed behaviour). Source-breaking for consumers reading/assigning the flag; no runtime behaviour change. Package-diff entries added for the removed public API. Part of #2053 (remove legacy feature flags, 7.0 breaking changes). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The flag defaulted to false on all targets and was never assigned by the framework, so SetUpdateControlTemplate() always updated the template eagerly (the `!UseLegacyLazyApplyTemplate` term was permanently true). Delete the flag and collapse SetUpdateControlTemplate to unconditionally call UpdateTemplate()/InvalidateMeasure(). Its `forceUpdate` parameter only mattered in the removed legacy path, so it is dropped and the one caller updated. The two Given_Control unit tests existed solely to exercise the legacy lazy sequence (asserting TemplatedRoot stays null until ApplyTemplate); they assert removed behaviour, so the file is deleted. Source-breaking for consumers reading/assigning the flag; no runtime behaviour change. Package-diff entries added for the removed public API. Part of #2053 (remove legacy feature flags, 7.0 breaking changes). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The flag defaulted to false on all targets and was never assigned by the framework, so DataTemplateHelper always fell back to the two-arg SelectTemplate(data, container) overload (WinUI-aligned). Delete the flag (and its now-empty FeatureConfiguration.DataTemplateSelector holder) and drop the flag term from the fallback condition. Source-breaking for consumers reading/assigning the flag; no runtime behaviour change. Package-diff entries added for the removed public API. Part of #2053 (remove legacy feature flags, 7.0 breaking changes). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The flag defaulted to false on all targets and was never assigned by the framework, so the Position of ManipulationStarted/Delta/Completed routed event args was always container-relative (WinUI-aligned). Delete the flag (and its now-empty FeatureConfiguration.ManipulationRoutedEventArgs holder) and inline the container-relative transform at the three call sites. Source-breaking for consumers reading/assigning the flag; no runtime behaviour change. Package-diff entries added for the removed public API. Part of #2053 (remove legacy feature flags, 7.0 breaking changes). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The flag defaulted to false on all targets and was never assigned by the framework, so PrepareManagedGestureEventBubbling always fell through to the specific-event prevention logic (the correct behaviour). Delete the flag and the dead CompleteGesture early-out that only ran when the flag was set. Source-breaking for consumers reading/assigning the flag; no runtime behaviour change. Package-diff entries added for the removed public API. Part of #2053 (remove legacy feature flags, 7.0 breaking changes). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Both flags defaulted to true on all targets and were never assigned by the framework, so the measure/arrange dirty-path was always used globally. Delete the flags and drop the flag term from the layout conditions. The legacy full-propagation `else` branches are intentionally kept: they remain reachable per-element through the still-supported FrameworkElementHelper.SetUseMeasurePathDisabled/SetUseArrangePathDisabled API (IsMeasureDirtyPathDisabled / IsArrangeDirtyPathDisabled), which is out of scope for this flag removal. Also rewrites the four <see cref> doc-comments in FrameworkElementHelper that referenced the removed flags (would otherwise be dangling / CS1574), and drops the obsolete global-flag toggles from the two UIElement layout samples (their per-element dirty-path demo and perf test are kept). Source-breaking for consumers reading/assigning the flags; no runtime behaviour change. Package-diff entries added for the removed public API. Part of #2053 (remove legacy feature flags, 7.0 breaking changes). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The flag's sole consumer sits under #if !UNO_HAS_ENHANCED_LIFECYCLE, so it is never read on Skia or WASM (removal is a true no-op there). Its default was platform-conditional (false on native Android/Apple, true otherwise), which made the observable behaviour a compile-time property, not a runtime one: - native Android/Apple: OnApplyTemplate applied immediately; - reference / unit-test flavor: deferred while !IsLoaded. Replace the runtime flag test with that same #if __ANDROID__ || __APPLE_UIKIT__ split so both behaviours are preserved exactly, and delete the flag. Verified: Uno.UI.Skia (compiled out) and Uno.UI.UnitTests / reference (#else deferred path) build clean. The native #if branch is the verbatim prior else-body. No runtime behaviour change. Package-diff entries added. Part of #2053 (remove legacy feature flags, 7.0 breaking changes). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The flag defaulted to false on all targets and was never assigned by the framework, so Popup.IsLightDismissEnabled already defaulted to false (WinUI-aligned). Delete the flag, pin the Popup default value to false, and remove the dead AutoSuggestBox workaround that only ran when the flag was set. Drops the corresponding feature-flags.md section. Source-breaking for consumers reading/assigning the flag; no runtime behaviour change. Package-diff entries added for the removed public API. Part of #2053 (remove legacy feature flags, 7.0 breaking changes). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The flag defaulted to false on all targets and was never assigned by the framework (SamplesApp set it to false explicitly), so the Skia-based TextBox (_isSkiaTextBox) was always used. Delete the flag, then inline _isSkiaTextBox as the constant true it had become: fold every guard, unwrap the always-taken branches, and delete the unreachable !_isSkiaTextBox branches in TextBox(.skia/.pointers.skia).cs and TextBoxView.skia.cs. In the shared TextBox.cs the #if __SKIA__ guards turn into inverted #if !__SKIA__ guards where the folded branch runs only on native, so native (WASM/Android/UIKit) behaviour is unchanged; OnKeyDownNonSkia, now unreachable on Skia, moves under #if !__SKIA__. The IOverlayTextBoxViewExtension layer is intentionally kept: it is still required for the invisible native text view (IME) on WASM-Skia and UIKit-Skia, gated by _useInvisibleNativeTextView independently of the removed flag. Tearing that extension layer down is native-overlay work that belongs with epic #2049's native drop. Tests: removed the flag save/restore no-ops; deleted the overlay-only When_FeatureConfiguration_Changes test; dropped the overlay case from the parameterized AutoSuggestBox test; simplified the Skia selection-start assertions to the skia-textbox value. Source-breaking for consumers reading/assigning the flag; no runtime behaviour change. Package-diff entries added for the removed public API. Part of #2053 (remove legacy feature flags, 7.0 breaking changes). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Contributor
|
🤖 Your WebAssembly Skia Sample App stage site is ready! Visit it here: https://unowasmprstaging.z20.web.core.windows.net/pr-23666/wasm-skia-net9/index.html |
Contributor
|
The build 220954 did not find any UI Test snapshots differences. |
MartinZikmund
approved these changes
Jul 7, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
GitHub Issue: unoplatform/uno-private#2053 — https://github.com/unoplatform/uno-private/issues/2053 (internal; cross-repo, not auto-closed)
PR Type:
💬 Other — Breaking change: removal of legacy
FeatureConfigurationpublic API. Source-breaking, behavior-preserving on shipping (Skia) targets. Targetsfeature/breakingchanges(7.0).What changed? 🚀
Removes 14 legacy
FeatureConfigurationflags that were permanently pinned to a single value on all shipping (Skia) targets and never assigned by the framework itself (only by SamplesApp/tests). For the 7.0 breaking major these are hard-removed (no[Obsolete]shim), and the live code path is inlined. This shrinks the public config surface with no runtime behavior change on shipping targets.One
refactor(scope)!commit per flag (BC33's twoInvalidate*Pathflags share one commit since they touch the same subsystem). Each commit builds green on its own and carries its ownPackageDiffIgnore.xmlentry,<see cref>fixes, and test/sample/doc cleanup.Binding.IgnoreINPCSameReferences(BC35)UIElement.UseLegacyHitTest(BC18)IsViewHit() => falseUIElement.ShowClippingBounds(BC46)Timeline.DefaultsStartingValueFromAnimatedValue(BC06)GetValueCore()VisualState.ApplySettersBeforeTransition(BC69)Control.UseLegacyLazyApplyTemplateControl.UseLegacyTemplateSelectorOverloadManipulationRoutedEventArgs.IsAbsolutePositionEnabledUIElement.DisablePointersSpecificEventPreventionFrameworkElement.UseInvalidateMeasurePath+UseInvalidateArrangePath(BC33)Control.UseDeferredOnApplyTemplate#ifsplit²Popup.EnableLightDismissByDefaultIsLightDismissEnableddefault pinnedfalseTextBox.UseOverlayOnSkia_isSkiaTextBoxinlinedtrue³¹ BC33: only the flag term is dropped from the conditions — the
elsefallback branches remain reachable via the still-live per-element APIFrameworkElementHelper.SetUseMeasurePathDisabled/SetUseArrangePathDisabled, which is not in this issue's scope.²
UseDeferredOnApplyTemplateis not a plain inline: its consumer sits under#if !UNO_HAS_ENHANCED_LIFECYCLE(defined for Skia + WASM), so on Skia/WASM the flag was never read. The removal replaces the flag test with#if __ANDROID__ || __APPLE_UIKIT__(immediate) /#else(deferred) to preserve native vs. reference behavior exactly.³
UseOverlayOnSkia:_isSkiaTextBoxis inlined as the constanttrueit had become; the always-taken branches are unwrapped and the unreachable!_isSkiaTextBoxoverlay branches removed. TheIOverlayTextBoxViewExtensionlayer is intentionally kept — still required for the invisible native text view (IME) on WASM-Skia / UIKit-Skia, gated independently of the removed flag.Deferred to epic #2049 (drop native targets)
Style.UseUWPDefaultStylesfamily (UseUWPDefaultStyles,UseUWPDefaultStylesOverride,ConfigureNativeFrameNavigation,SetUWPDefaultStylesOverride<T>) — during implementation this proved to be native-styling subsystem removal (publicStyleHelperdeletion,RegisterDefaultStyleForTypesignature change, XAML-generator edits +Generic.Native.xamldeletion, runtime-test cascade), not a flag inline. It belongs with the native drop, so this PR leaves it untouched.Out of scope (behavior flips — routed to Phase 5, not this PR)
UseLegacyContentAlignment(BC45) andUseLegacyPrimaryLanguageOverride(BC50) — these change runtime defaults and need fails-before/passes-after tests.Tests / docs
UseLegacyLazyApplyTemplatetests inGiven_Control.cs, the overlay-onlyWhen_FeatureConfiguration_Changes); removed flag save/restore no-ops; de-parameterized the overlay case out of the AutoSuggestBox test.App.xaml.cs.doc/articles/feature-flags.md: removed the Light Dismiss Default section.build/PackageDiffIgnore.xml: added an ignore entry for every removedpublic staticmember (and the removed empty holder nested types) under the6.6baseline set, so the API-diff gate stays green.Verification
Uno.UI.Skia(net10.0); flags with#if !UNO_HAS_ENHANCED_LIFECYCLEconsumers also built the Reference flavor; BC33 +UseOverlayOnSkiaadditionally builtUno.UI.RuntimeTests.SkiaandSamplesApp.Skia.Generic.PackageDiffIgnore.xmlentries clear the API-diff gate on CI (not reproducible locally).PR Checklist ✅
feature-flags.md) where a removed flag was documentedScreenshots Compare Test RunresultsBreaking change — impact & migration
This PR removes public
FeatureConfigurationflags (7.0 breaking major). Impact: code that reads or assigns any of the 14 flags above will no longer compile. Migration: delete those assignments — every flag was pinned to its non-legacy value on shipping targets, so removing the assignment matches current runtime behavior. Covered by the 7.0 migration notes.