Repository navigation
[iOS] Restore large-title scrolling for nested compatibility lists - #39502
jfversluis wants to merge 181 commits into
Conversation
Updated [Microsoft.AspNetCore.Authentication.Facebook](https://github.com/dotnet/dotnet) from 10.0.0 to 10.0.10. <details> <summary>Release notes</summary> _Sourced from [Microsoft.AspNetCore.Authentication.Facebook's releases](https://github.com/dotnet/dotnet/releases)._ No release notes found for this version range. Commits viewable in [compare view](https://github.com/dotnet/dotnet/commits). </details> Updated [Microsoft.AspNetCore.Authentication.Google](https://github.com/dotnet/dotnet) from 10.0.0 to 10.0.10. <details> <summary>Release notes</summary> _Sourced from [Microsoft.AspNetCore.Authentication.Google's releases](https://github.com/dotnet/dotnet/releases)._ No release notes found for this version range. Commits viewable in [compare view](https://github.com/dotnet/dotnet/commits). </details> Updated [Microsoft.AspNetCore.Authentication.MicrosoftAccount](https://github.com/dotnet/dotnet) from 10.0.0 to 10.0.10. <details> <summary>Release notes</summary> _Sourced from [Microsoft.AspNetCore.Authentication.MicrosoftAccount's releases](https://github.com/dotnet/dotnet/releases)._ No release notes found for this version range. Commits viewable in [compare view](https://github.com/dotnet/dotnet/commits). </details> Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) --- <details> <summary>Dependabot commands and options</summary> <br /> You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore <dependency name> major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore <dependency name> minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore <dependency name>` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore <dependency name>` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore <dependency name> <ignore condition>` will remove the ignore condition of the specified dependency and ignore conditions </details> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
<!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ### Description of Change Removes the private `DropCompletedEventArgs.DropResult` property. The property was never assigned or consumed and always held its default value. `DropCompletedEventArgs` remains useful through its public `PlatformArgs` property. This does not change the public API surface. ### Issues Fixed Fixes #2839
…ating project cards (#37385) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ### Issue Details The voice-over does not announce the project description when the focus moves to the border element within the item template of the CollectionView on the Mac platform. ### Root Cause SemanticProperties.Description was bound only to the project Name on the parent Border. Because the card is exposed as one accessible/selectable element, VoiceOver does not announce the child labels separately ### Description of Change Combined both Name and Description values into the Border semantic description. ### Issues Fixed Fixes #37142 **Tested the behavior in the following platforms.** - [x] Android - [x] Windows - [x] iOS - [x] Mac | Before | After | |---------|--------| | <video src="https://github.com/user-attachments/assets/20884ac2-7f4c-4907-8d97-02326a093be2" Width="600" Height="400"/>| <video src="https://github.com/user-attachments/assets/c0f63c4e-4e12-4af4-976d-439970db7a67" Width="600" Height="400"/> |
…ist item (#37340) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ### Issue Details Issue Details When a VisualStateGroup is replaced through the VisualStateGroupList indexer, the existing implementation only updates the internal list: `visualStateGroups[index] = replacementGroup;` The replacement bypasses the lifecycle behavior used by Add, Insert, and Remove: * The old group remains subscribed to StatesChanged. * The replacement group is not subscribed to StatesChanged. * Group and state names are not revalidated. * State triggers are not updated for the replacement. * The associated VisualElement is not notified to reevaluate its visual state. ### Description of Change <!-- Enter description of the fix in this section --> * Updated the VisualStateGroupList indexer setter to correctly manage group replacement: * Reject null replacement values with ArgumentNullException. * Unsubscribe ValidateAndNotify from the replaced group. * Replace the group in the internal collection. * Subscribe ValidateAndNotify to the new group. * Explicitly call ValidateAndNotify(_internalList) after replacement. ### Issues Fixed <!-- Please make sure that there is a bug logged for the issue being fixed. The bug should describe the problem and how to reproduce it. --> Fixes #37171 <!-- Are you targeting main? All PRs should target the main branch unless otherwise noted. --> **Tested the behavior in the following platforms.** - [x] Android - [x] Windows - [x] iOS - [x] Mac | Before | After | |---------|--------| | **Android**<br> <img src="https://github.com/user-attachments/assets/1e6c5337-afcc-4e55-bba2-6852316fdf6a" width="300" height="600"> | **Android**<br> <img src="https://github.com/user-attachments/assets/006f5544-3393-4f3a-9774-86ff6d966947" width="300" height="600"> |
…me instead of item content in Narrator (#37421) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ### Root Cause On Windows, `CollectionView`'s legacy handler (CV1), which is based on `ListView`, derives each item's screen reader name from the root element of the `DataTemplate`. When neither `AutomationProperties.Name` nor `SemanticProperties.Description` is set on that root element, WinUI falls back to calling `.ToString()` on the bound item. As a result, Narrator announces the internal type name: `Microsoft.Maui.Controls.Platform.ItemTemplateContext` instead of meaningful item content. This is native WinUI `ListView` behavior documented by Microsoft and is not specific to MAUI. ### Description of Change Set `SemanticProperties.Description` on the `DataTemplate` root, `TaskView`'s `Border`, and scope it to Windows only. This ensures Narrator announces the bound task title instead of the internal type name. Windows-only scoping is necessary because applying `SemanticProperties.Description` on iOS and Mac Catalyst causes the root element to become a single accessibility element, preventing VoiceOver from navigating to the inner `CheckBox`. ### Issues Fixed Fixes #36940 ### Platforms Tested - [x] iOS - [x] Android - [x] Windows - [x] Mac ### Screenshots | Before Fix | After Fix | |------------|-----------| | <video width="350" alt="withoutfix" src="https://github.com/user-attachments/assets/b35e24bc-0c59-4db1-8210-1be4fe5c2333" /> | <video width="350" alt="withfix" src="https://github.com/user-attachments/assets/89ad2456-5c9d-4060-8685-e108e9fe8c3e" /> |
<!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ### Description Fixes #29418. On Windows, `W2DGraphicsView` stored Win2D's callback-scoped `CanvasDrawingSession` on its persistent canvas. Win2D disposes that native session after the draw callback returns, but the stale managed reference remained available across repeated pointer-driven redraws and shutdown, leading to native access violations and heap corruption. This change clears the drawing session after canvas state has been reset. The nested cleanup guarantees the session and thread-local canvas owner are released even if state reset throws. @Kamalesh-Periyasamy, once the PR artifacts are available, could you please try them with your original application and let us know whether they resolve the crash? ### Tests - Added a Windows device test that performs an initial draw plus 100 explicit invalidation/draw cycles and verifies the drawing session is released after every callback. - Verified the test fails without the fix by observing the retained, already-disposed `CanvasDrawingSession`. - Core DeviceTests: 2,092 total, 1,981 passed, 111 skipped, 0 failed. - Ran the exact issue attachment twice for 120 seconds each with 3,848 presses and 38,480 pointer moves per run; both exited cleanly with code 0 and no correlated Windows application errors. - Also validated custom/default fonts, `ManipulationMode.All`/`None`, multiple views, redraw, resize, unload, and graceful shutdown. ### Video verification #### Before — original reported crash The issue author's original recording shows the attached app failing during pointer interaction: https://github.com/user-attachments/assets/eecd8e89-17c9-4764-b21e-9e6c15141fb4 #### After — fixed DLL under sustained pointer stress The exact attached application was rebuilt with an ABI-compatible fixed `Microsoft.Maui.Graphics.Win2D.WinUI.Desktop.dll`, then exercised with real `SendInput` pointer presses and moves for 120 seconds: https://github.com/user-attachments/assets/41a3e68c-e048-4d09-b677-aec1a9bc3af7 This recorded run delivered 11,622 presses and 116,220 pointer moves, then closed normally with exit code `0`. No correlated `Application Error` or `.NET Runtime` event was recorded. The native crash is intermittent: fresh recording attempts against the original DLL did not fail during the capture session, so the before clip above is the reporter's genuine original failure rather than a clean run being mislabeled or a crash being staged. The deterministic regression evidence is the baseline test retaining an already-disposed `CanvasDrawingSession`; the same test passes after this change. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 01dac3d5-7cea-4af6-ba68-fdc87f9ceb54
…ains prior ShellContent instances (#37390) <!-- Please keep the note below for people who find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment whether this change resolves your issue. Thank you! ### Description of Change **Memory management and event subscription improvements:** * Adds a destructor (`~ShellContent`) to `ShellContent` that unsubscribes from property change notifications, preventing memory leaks when a shared `Page` is assigned to multiple transient `ShellContent` instances (`src/Controls/src/Core/Shell/ShellContent.cs`). * Refactored event subscription logic to use `WeakNotifyPropertyChangedProxy` and a cached handler, ensuring that event handlers do not prevent garbage collection of `ShellContent` instances (`src/Controls/src/Core/Shell/ShellContent.cs`). **Testing and regression coverage:** * Adds a unit test to verify that assigning the same long-lived `Page` to many transient `ShellContent` instances does not retain those instances in memory, addressing issue #37217 (`src/Controls/tests/Core.UnitTests/ShellTests.cs`). **Public API updates:** * Adds destructor signature for `ShellContent` to the platform-specific `PublicAPI.Unshipped.txt` files to document the new public API surface (`src/Controls/src/Core/PublicAPI/net-android/PublicAPI.Unshipped.txt`, `src/Controls/src/Core/PublicAPI/net-ios/PublicAPI.Unshipped.txt`, `src/Controls/src/Core/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt`, `src/Controls/src/Core/PublicAPI/net-tizen/PublicAPI.Unshipped.txt`, `src/Controls/src/Core/PublicAPI/net/PublicAPI.Unshipped.txt`, `src/Controls/src/Core/PublicAPI/netstandard/PublicAPI.Unshipped.txt`, `src/Controls/src/Core/PublicAPI/net-windows/PublicAPI.Unshipped.txt`). [[1]](diffhunk://#diff-4731d7bdf78f0e9d2a7a64d6f56502e3d2095313d039e7f09c0e7d1552471f8eR25) [[2]](diffhunk://#diff-793476570313a2965972f9be2c01f3eaaf5eec16dfab1b6b7e34cd5473af4277R18) [[3]](diffhunk://#diff-b98fb401b945e281e04d9aabd0695677c639da1423ae935f1e521e88e8cae021R8) [[4]](diffhunk://#diff-923a9c83577000b182ef448083ba67a73bd622126eafbd11d265afe0e2387a68R10) <!-- Enter description of the fix in this section --> ### Issues Fixed <!-- Please make sure that there is a bug logged for the issue being fixed. The bug should describe the problem and how to reproduce it. --> Fixes #37217 ### Tested the behavior in the following platforms - [x] Windows - [x] Android - [x] iOS - [x] Mac | Before Issue Fix | After Issue Fix | |---|---| | <video src="https://github.com/user-attachments/assets/c8166be4-b3b0-4706-8a38-ebfc6778f6ff"> | <video src="https://github.com/user-attachments/assets/c26f1915-2152-4c5e-b923-2659a5b13f3a"> | <!-- Are you targeting main? All PRs should target the main branch unless otherwise noted. -->
… to its condition by configuration/target (#37176) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ### Issue Details MauiXaml will generate source for every xaml file without respect to its condition by configuration/target ### Root Cause • Microsoft.Maui.Controls.Globs.props globs **\*.xaml into the MauiXaml item group unconditionally for every inner build/TFM. • Microsoft.Maui.Controls.SingleProject.targets correctly gates Compile ( .cs ) items under Platforms/<Platform>/ via %(Compile.ExcludeFromCurrentConfiguration) , but its XAML-removal logic only ever stripped Windows .xaml (WinUI markup) out of MauiXaml . It never removed non-active-platform .xaml under Platforms/Android , Platforms/iOS , Platforms/MacCatalyst , or Platforms/Tizen . • Consequence: the XAML SourceGen consumes MauiXaml as AdditionalFiles regardless of platform, so every platform's xaml leaked into every inner build — producing duplicate InitializeComponent /attribute/field declarations whenever multiple platforms reused the same class name (a standard, supported pattern). ### Description of Change src/Controls/src/Build.Tasks/nuget/buildTransitive/netstandard2.0/Microsoft.Maui.Controls.SingleProject.targets (shipped via buildTransitive in Microsoft.Maui.Controls.Build.Tasks → applies to every MAUI app) Extended the _MauiRemovePlatformCompileItems target's _MauiXamlToRemove computation (previously Windows-only) to also cover Android/iOS/MacCatalyst/Tizen: for each built-in platform folder, its .xaml files are queued for removal from MauiXaml / EmbeddedResource unless it matches the currently active $(TargetPlatformIdentifier) . The pre-existing unconditional Windows-folder removal (WinUI markup, not MAUI XAML) is left unchanged. ### Issues Fixed Fixes #36951 **Tested the behavior in the following platforms.** - [x] Android - [x] Windows - [x] iOS - [x] Mac | Before | After | |---------|--------| | <img src="https://github.com/user-attachments/assets/a0fd36d9-2094-4948-a645-c3c0d1bf0e4e" Width="600" Height="300" /> | <img width="600" height="300" alt="image" src="https://github.com/user-attachments/assets/510d9024-dacc-4447-821d-29e7129ed844" /> |
### Description of Change Captures the weak-reference fields in local variables before testing and dereferencing them. This closes the time-of-check/time-of-use race with `Unsubscribe()`, which clears the fields concurrently. The race has been observed as an unhandled Android `NullReferenceException` from both `TryGetSource` during binding finalization and `TryGetHandler` while processing property changes. ### Issues Fixed Fixes #32602 ### Validation - `dotnet build src/Controls/src/Core/Controls.Core.csproj --no-restore --verbosity minimal -p:TargetFramework=netstandard2.0` Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
## Description Keeps `VisualElement.IsVisible` as the locally assigned/bound value while making handler-facing `IView.Visibility` reflect cumulative visibility through the visual ancestor chain. Effective visibility changes are cached and propagated through the existing property-propagation pipeline. Unchanged branches are pruned, so descendant handlers and measure invalidation run only for actual effective visibility transitions. Reparenting and detaching are covered. Fixes #19139. ## Regression tests - Hidden and nested ancestors - Ancestor visibility changes without mutating child `IsVisible` - Reparenting and detaching - Non-layout visual children - Handler mapping and unchanged-branch pruning - Measure invalidation ## Validation - `VisualElementTests`: 29 passed - `Issue1549` XAML compatibility tests: 3 passed - iOS runtime: `IsVisible` remains `True`, `IView.Visibility` is `Collapsed`, and keyboard Next skips the hidden entry - Android runtime: `IsVisible` remains `True`, `IView.Visibility` is `Collapsed`, and IME Next skips the hidden entry ---------
…eak Device Test (#37310) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! <!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> ### Issue Details Device memory leak tests started failing in the Candidate branch after PR #35487, indicating regressions in memory leak validation across Windows, iOS, macOS, and Android. The affected Does Not Leak and Window Does Not Leak tests were failing on these platforms. ### Issue1: Window Does Not Leak ### Root cause The WindowDoesNotLeak test failed intermittently because window and page were declared as locals inside an async Task method ( WindowDoesNotLeak ) and were referenced across await boundaries (both directly and inside the lambda passed to CreateHandlerAndAddToWindow ). The C# compiler hoists such locals into fields of the generated async state machine, and those fields are not guaranteed to be cleared once the locals are no longer needed. As a result, window and page remained artificially rooted by the state machine instance for the entire duration of the subsequent WaitForGC call, producing a false-positive "still alive" leak report rather than reflecting an actual product defect. ### Solution description The fix extracts the window/page creation and handler invocation logic out of WindowDoesNotLeak into a new, non-inlineable helper method, CreateWindowLeakReferencesAsync , marked with [MethodImpl(MethodImplOptions.NoInlining)] . This helper creates window and page , drives the handler lifecycle, and returns only the collected WeakReference list. Since window and page now live in the helper's own async state machine — which is discarded once the helper returns — they are no longer reachable from WindowDoesNotLeak 's state machine during the subsequent WaitForGC call, eliminating the artificial rooting. The dead conditional compilation guard ( #if TEST_FAILS_ON_ANDROID && TESTS_FAILS_ON_WINDOWS && TESTS_FAILS_ON_IOS && TESTS_FAILS_ON_MACCATALYST ) that had disabled the test was also removed to re-enable it. ### Issue2: TabbedPageTests.DoesNotLeak ### Root cause The issue occurs because of two compounding factors. At the test level, the navPage local was captured by an async lambda and accessed again after an await , causing it to be hoisted into the compiler-generated closure and transitively keep the popped TabbedPage alive through its navigation stack. At the platform level on Android, MultiPageFragmentStateAdapter was constructed using the host Activity's long-lived Lifecycle , causing AndroidX to permanently register a lifecycle observer that was never released because the Activity's lifecycle never reached the destroyed state. This kept the adapter, and the TabbedPage it referenced, permanently rooted in memory, while AndroidX also failed to reclaim the associated child fragments. ### Solution description The fix involves nulling the navPage local before the WaitForGC call at the test level, combined with a production-level Android fix in MultiPageFragmentStateAdapter.cs that introduces a teardown routine to make AndroidX reclaim its fragments correctly and explicitly clears the adapter's page reference on disposal. Supporting changes in TabbedPageManager.cs and TabbedPage.Android.cs ensure the teardown routine executes before the adapter is detached and that manager references are cleared on disconnect. The resolution was verified through repeated on-device Android test runs, all passing successfully. ### Issue3: NavigationPageTests.DoesNotLeak ### Root Cause The issue occurs because of the `navPage` and `window` locals in `NavigationPageTests.DoesNotLeak` being referenced across an `await` boundary — both directly and inside the lambda passed to `CreateHandlerAndAddToWindow`. The C# compiler hoists such locals into fields of the generated async state machine for the test method, and those fields are not guaranteed to be cleared once the locals are no longer needed. As a result, `navPage` and `window` remained artificially rooted by the state machine instance for the duration of the subsequent `WaitForGC` call, producing a false-positive "still alive" leak report rather than reflecting an actual product defect. This issue was only replicated in Release mode, since Release-mode JIT/compiler optimizations affect how and when the hoisted state-machine fields are cleared, whereas Debug builds happened to clear or avoid rooting them, masking the problem locally. ### Solution Description The fix involves extracting the `navPage`/`window` creation and handler invocation logic out of `DoesNotLeak` into a new, non-inlineable helper method, `CreateNavigationPageLeakReferencesAsync`, marked with `[MethodImpl(MethodImplOptions.NoInlining)]`. This helper creates `navPage` and `window`, drives the handler lifecycle, and returns only the collected `WeakReference` list. Since `navPage` and `window` now live in the helper's own async state machine — which is discarded once the helper returns — they are no longer reachable from `DoesNotLeak`'s state machine during the subsequent `WaitForGC` call, eliminating the artificial rooting. Validated the behavior in the following platforms - [x] iOS - [x] Mac - [x] Android - [x] Windows ### Regression PR PR #35487 ### Issues Fixed Fixes #36613 ### Output Screenshot ### Issue1: Window Does Not Leak |Platform|Before|After| |--|--|--| |Android| <video src="https://github.com/user-attachments/assets/1d3986aa-5c5f-4d97-ab6e-96c586e53488" >| <video src="https://github.com/user-attachments/assets/3670bafa-6a75-47a8-8505-797901e7abeb">| |Mac|<video src="https://github.com/user-attachments/assets/461534f8-21dd-46ab-bb62-c10a5f8ac71a"> |<video src="https://github.com/user-attachments/assets/d862eb7f-c33f-4866-a553-5264b1cda411">| |iOS|<video src="https://github.com/user-attachments/assets/41b71c49-26ac-4dcc-9e01-87dce42d5000">|<video src="https://github.com/user-attachments/assets/9e03f7ca-d803-49b9-a159-4057320591a7">| |Windows|<video src="https://github.com/user-attachments/assets/73300a73-a9be-403b-b77e-2cc4418d10c9">|<video src="https://github.com/user-attachments/assets/173cf2e3-5bde-4383-b07a-0b6b8422d03b"> | ### Issue2: TabbedPageTests.DoesNotLeak |Platform|Before|After| |--|--|--| |Android| <video src="https://github.com/user-attachments/assets/604316e5-5849-4195-9e16-1c96d710c125" >| <video src="https://github.com/user-attachments/assets/50bc614c-814d-43d1-912b-446886086886">| ### Issue3: NavigationPageTests.DoesNotLeak |Platform|Before|After| |--|--|--| |Mac|<video src="https://github.com/user-attachments/assets/cd6831a8-e8f6-4954-baff-055a2575a576"> |<video src="https://github.com/user-attachments/assets/6198e780-82e9-4eec-b3f5-a805f79d0ddd">| |iOS|<video src="https://github.com/user-attachments/assets/47edefd0-a416-4245-bbce-3e54c80aefa0">|<video src="https://github.com/user-attachments/assets/84f2c31c-0d9d-4c3e-9f21-9a8f634e671f">|
<!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! On Windows, propagate `InputTransparent` to a view's `WrapperView` as well as its inner platform view. This allows pointer input to pass through wrapped controls, including the default-template `Label` with a transparent background overlaying a `Button` from #21384. The fix preserves two important Windows behaviors: - `ILayoutHandler` continues using `LayoutPanel`'s specialized background-based input transparency, so transparent layouts do not disable their interactive child tree. - Reusing a disconnected handler preserves the existing wrapper and its visual-tree position while replacing its stale child with the newly created platform view. Framework reconnect creates and connects the replacement platform view unparented before mapper replay. The reconnect repair therefore only updates `WrapperView.Child`; it does not remove the platform view from arbitrary parent shapes or re-enter virtual `SetupContainer()` overrides that could duplicate subscriptions or one-time setup. Normal mapper replay restores Label/Image sizing and alignment after the child replacement. The default template's implicit `Label` style supplies a transparent background, which causes `LabelHandler` to create a Windows `WrapperView`. The existing mapper disabled hit testing only on the inner `TextBlock`; the effective wrapper remained hit-testable and intercepted pointer input. - Windows Label device tests: **42 total, 40 passed, 0 failed, 2 skipped**. Coverage includes initial state, runtime toggles, late wrapper creation, reconnect hit testing and mapped properties, the framework's unparented replacement-platform-view lifecycle, a wrapper moved to another attached `Panel`, and a detached wrapper. - Failure-first reconnect validation: temporarily removing the reconnect rebinding made all three reconnect-specific tests fail; restoring it made them pass. - Windows Layout device tests: **54/54 passed**, covering both `CascadeInputTransparent` modes and confirming that the wrapper remains hit-testable for child interaction. - Windows Core tests: **1,980 passed, 0 failed, 111 skipped**; the exact CI-reported Slider case and all 90 Slider tests passed locally. - Windows Appium test and HostApp builds completed with **0 warnings and 0 errors**, and both Issue21384 tests are discovered. The reporter-faithful Label pointer test is skipped on MacCatalyst because test remains cross-platform. - Local Appium execution remains blocked before interaction by WinAppDriver's invalid status response. The real Win32 `SendInput` harness below provides behavior-level evidence. Both recordings use the same `AbsoluteLayout` reproduction from #21384 and send five real Win32 mouse clicks to the overlaid button (`SendInput`, not UI Automation invoke). **Before — bug reproduced on parent commit `f377ff1c5e`:** all five clicks are sent, but the click handler receives none and the visible counter remains at 0. https://github.com/user-attachments/assets/d59d3346-355c-434f-b1ac-01c76c361ab1 **After — fixed behavior:** all five equivalent clicks reach the button and the visible counter advances from 0 to 5. The final production code was rerun with the same harness and again received **5/5** clicks. https://github.com/user-attachments/assets/610856db-c094-4657-b4ea-0985b96221dd - Do not update only the inner Windows platform view; a hit-testable `WrapperView` can still intercept input. - Do not disable the wrapper for `ILayoutHandler`; `LayoutPanel` intentionally preserves child interaction through its background-based mapper. - Do not re-enter virtual `SetupContainer()` during reconnect; derived handlers may repeat subscriptions or one-time side effects. - Do not add generalized parent-detachment logic for reconnect; the framework replacement platform view is unparented before mapper replay, and the surviving wrapper's parent must remain unchanged. Fixes #21384 @owaits, once the build artifacts are available, could you please try them with your original reproduction and let us know whether this resolves the issue for you? --------- Co-authored-by: Jakub Florkowski <42434498+kubaflo@users.noreply.github.com>
… and callbacks alive (#37639) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! <!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> ### Issue Details - Disposing `AnimationManager` did not release the manager, active animations, or callback-captured data when its `ITicker` remained alive. ### Root Cause of the Issue - `AnimationManager` assigns `OnFire` to `Ticker.Fire` and stores active animations in `_animations`. Its previous `Dispose()` implementation only disposed tickers implementing `IDisposable`; it did not remove `OnFire`, stop a normal `ITicker`, or clear `_animations`. Consequently, a long-lived ticker could retain the entire object graph. ### Description of Change <!-- Enter description of the fix in this section --> ### Improvements to resource management and disposal: * Refactored the `Dispose` method in `AnimationManager` to ensure it is idempotent, detaches event handlers, clears animations, and disposes of the ticker only when appropriate. This prevents multiple disposals and ensures resources are released correctly. ### New unit tests for disposal behavior: * Added `AnimationManagerTests` with tests to verify: - The ticker callback is released without disposing the animation. - Animation payloads are released when the ticker outlives the manager. - The owned callback is properly removed from multicast delegates. - Correct disposal and stop counts for the ticker. - No unintended side effects on animation callbacks after disposal. ### Issues Fixed <!-- Please make sure that there is a bug logged for the issue being fixed. The bug should describe the problem and how to reproduce it. --> Fixes #37228 ### Tested the behavior in the following platforms - [x] Windows - [x] Android - [x] iOS - [x] Mac ### Output | Before | After | |----------|----------| | <img src="https://github.com/user-attachments/assets/fe7e8c32-eb2c-4808-bc8b-599aa7055344"> | <img src="https://github.com/user-attachments/assets/83fe5ec1-6462-4942-a461-034f3d25407b"> | <!-- Are you targeting main? All PRs should target the main branch unless otherwise noted. -->
<!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! Fixes #17523 Windows attached the Border's `CompositionGeometricClip` directly to the content visual while authoring the geometry in the parent `ContentPanel` coordinate space. Scale, rotation, and translation therefore transformed the clip together with the content instead of keeping the Border aperture stationary. - Place Border content inside a Border-only stationary native clip host and attach the geometric clip to that host. - Route cross-platform measure invalidation to both native layers while preserving WinUI's cached subtree measure on unrelated parent layout passes. - Avoid re-entering measure from arrange when a layout owner changes; the normal invalidated measure pass remains authoritative. - Preserve the cross-platform arranged size through the native clip host, including detached and reconnected layout-owner transitions. - Cache stable composition and rectangular bounds clip geometry, rebuilding only when geometry inputs change. - Tear down layout owners, hosted content, stroke references, and cached clip state when the handler disconnects, after derived handler disconnect hooks have observed the intact platform view. - Safely ignore late invalidation after handler disconnect and synchronize direct or reconnect-driven layout-owner changes with the clip host. - Preserve current cross-parent content reparenting while clearing stale clip-host ownership when content moves Border → Border, Border → generic `MauiPanel`, or back again. - Handle zero-by-infinite WinUI measure constraints without invoking cross-platform layout. - Keep layout invalidation flowing for initial asynchronous image loads and runtime content-size, `FontSize`, and `Padding` changes without requiring an outer window resize. - Preserve explicit Border sizing, stroke/shadow behavior, nested layout clipping, content replacement, custom handler activation and mapper customization, shape removal, and accessibility behavior. - Clamp stroke-inset geometry to nonnegative dimensions and preserve an explicitly empty aperture when the stroke consumes all available content space, including rounded shapes. - Clear stale clipping geometry whenever either arranged dimension is non-positive. - Remove the obsolete nested `LayoutPanel` clip exception because the XAML rectangular clip and Border composition clip now live on separate visuals. - Update the three affected WinUI Image AspectFill baselines for the stationary clip host's one-pixel antialiased inner edge; image content remains pixel-identical. This is an implementation-only Windows fix; it adds no public APIs. **Before — issue author's attached reproduction, minimally retargeted to the current Windows TFM:** transformed image content escapes the stationary ellipse, rounded rectangle, and triangle apertures as image scale changes. https://github.com/user-attachments/assets/7cf6b0fc-c101-44df-ba5b-841131014708 **After — final reviewed PR gallery build using the exact `BorderResizeContent` source scenario:** the same scale interaction changes the image while each Border aperture remains stationary and correctly clips its content. https://github.com/user-attachments/assets/97a4429a-c32c-4c9f-9252-957b8f2c5e8f Both recordings use a 1280×720 window. Pixel analysis of the recorded scale-4 frames detected transformed image pixels outside the three Border regions before the fix and **0 outside after the fix**. - Windows Border device tests: **38 passed, 0 failed, 0 skipped, 0 errors**. - Added coverage for scale, rotation, translation, combined transforms, shadows, nested layouts, initial asynchronous image rendering, runtime `FontSize` and `Padding`, explicit sizing, content replacement, shape removal, disconnect/reconnect, derived disconnect ordering, teardown cleanup, direct layout-owner changes, derived handlers, clip ownership, cross-host and generic-parent reparenting, composition and bounds clip reuse, zero-by-infinite constraints, stroke-consuming zero-interior geometry, rounded empty apertures, cross-platform arranged-size propagation, automation, and layout-cache reuse. - Exact final `BorderResizeContent.xaml` gallery proof ran without resizing the window: - Image scale 1 → 4 changed 14,673 pixels inside the Border shapes and 0 outside. - Font size 40 → 120 changed 11,584 pixels inside the Border shapes and 0 outside. - All images rendered on initial load. - The repository's production `MagickNetVisualComparer` passes all three updated WinUI Image AspectFill snapshots at the default 0.005 RMS threshold. The accepted delta is confined to the one-pixel Border edge with zero changed pixels in the image interior. - Multiple independent MAUI expert, adversarial, and layout/performance reviews completed with no remaining actionable findings. @jstedfast, could you please test the PR artifacts against the original `BorderResizeContent` reproduction and confirm that initial rendering, transformed clipping, runtime font-size changes, and resizing now behave correctly? Co-authored-by: Jakub Florkowski <42434498+kubaflo@users.noreply.github.com>
…'s task (#37666) ### Description of Change Follow-up to #37409 (itself a follow-up to #37060), closing three holes of the same species in the deferred element-scroll machinery: **a request that ends without its task completing, or whose completion runs on the wrong stack.** Two are permanent hangs of `await ScrollToAsync(...)`; one is reachable by entirely ordinary code. 1. **A parked request displaced by any newer `ScrollToAsync` orphaned the first caller's task** — two calls in a row (say, both from `OnAppearing` before the first layout) and the first `await` never returns. Nothing else ever completes it: the superseding request creates a fresh completion source, and the `TaskStatus.Running` check in `CheckTaskCompletionSource` is dead code (a TCS-backed task reports `WaitingForActivation`, never `Running`, so the `TrySetCanceled` there is unreachable). This is the headline fix. 2. **Yielding the replay to a re-entrant `ScrollToRequested` subscriber abandoned the superseded caller's task** — same mechanism, narrower trigger (a legacy renderer issuing its own `ScrollToAsync` from inside the replayed event): permanent hang. 3. **The lifecycle-drop completion ran the caller's continuation from inside `Element.SetParent`**, before `OnPropertyChanged(nameof(Parent))` fires — caller code observing/mutating a half-propagated parent change. **One primitive fixes all three.** `CompleteWithoutScroll(completion)` captures the completion source **as a value** and posts `TrySetResult(true)` through the dispatcher: - **off the mutation stack** (fixes 3) — the continuation never runs inside `SetParent`/handler-change; - **bound by identity** (preserves the invariant from #37409's review rounds) — the post cannot read the field at fire time, so a newer request swapping `_scrollCompletionSource` in the window can never be released in the old request's place; - **applied at every point a request ends without its scroll** — the drop paths (detach, tree-removal, orphaned target), the yielded replay (fixes 2), and the supersede in `OnScrollToRequested` (fixes 1). The ordinary platform-callback completion (`SendScrollFinished` when a scroll actually happens) is untouched, so `await ScrollToAsync(...)` timing on the normal path is unchanged. Completing (rather than cancelling) a superseded task matches the existing drop semantics — no `await` in this API's history has thrown on supersede, and introducing `TaskCanceledException` would be a new public behavior. The contract comment now names all three exits from the park — replayed, superseded, dropped — so the stated contract and the code have no gap. No new public API. ### Issues Fixed Follow-up to #37409 / #37060 (fixes for #36801). ### Tests Every fix is pinned by a test **proven to fail with that fix reverted**: - `SupersedingAParkedRequestCompletesTheSupersededCallersTask` — both supersede shapes (direct send, and park-in-place) - `ReentrantRequestFromTheReplayedEventSupersedesTheReplay` — extended to assert the superseded caller is released - `DropCompletionIsPostedNotRunOnTheMutationStack` — dispatcher-capture harness: task pending after `Remove` returns, exactly one post queued, completes when it runs - `PostedDropCompletionReleasesOnlyTheDroppedTaskEvenIfANewRequestArrivesFirst` — the identity property: a new request arriving before the post runs is untouched; the dropped task completes (this test fails against a field-reading post, the bug shape from #37409's review) Verified on the merged `inflight/current` base: `ScrollViewUnitTests` 42/42 (10 consecutive runs), `Issue36801` + `Issue36801DeferredElement` + `ShellFlyoutHeaderScrollViewContent` iOS UI suites 12/12 on the simulator. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
… static event with WeakEventManager (#37382) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! <!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> ### Issue Details VisualDiagnostics.VisualTreeChanged is a public static event used by XAML Hot Reload, live visual-tree inspectors, and diagnostic tools. Because it is a plain multicast event, every subscriber is held by a strong reference in the invocation list. Any page, view, or object that subscribes stays alive until it explicitly calls -=, silently leaking the entire visual subtree, bindings, and view models. ### Root Cause The event was a normal static event — .NET stores subscribers with strong references. Since it's static, the list lives for the app's lifetime, so every subscriber lives forever too. The only way to escape was to explicitly write -=, which most callers forget. ### Description of Change Backed the event with a WeakEventManager (MAUI's built-in weak-event helper), so subscribers are held weakly and can be GC'd. The public event signature is unchanged — callers don't need to change anything. Validated the behavior in the following platforms - [x] Android - [x] Windows - [x] iOS - [x] Mac ### Issues Fixed Fixes #37242 ### Fix reference : [maui/src/Controls/src/Core/Application/Application.cs at bf62313 · …](https://github.com/dotnet/maui/blob/bf62313db2cecf3215f10c353720b341aba0a4ee/src/Controls/src/Core/Application/Application.cs#L263) [maui/src/Controls/src/Core/Command.cs at bf62313 · dotnet/maui](https://github.com/dotnet/maui/blob/bf62313db2cecf3215f10c353720b341aba0a4ee/src/Controls/src/Core/Command.cs#L128) [maui/src/Controls/src/Core/ImageSource.cs at bf62313 · dotnet/maui](https://github.com/dotnet/maui/blob/bf62313db2cecf3215f10c353720b341aba0a4ee/src/Controls/src/Core/ImageSource.cs#L175) ### Output ScreenShot |Before|After| |--|--| | <video src="https://github.com/user-attachments/assets/8b1d453a-dedd-48d0-a01d-aae7c7523f82" >| <video src="https://github.com/user-attachments/assets/824df312-de3c-4c4e-b073-9239b7c9d5c9">|
<!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ### Description of Change On Windows, mouse-wheel scrolling could update `CarouselView.Position` from native `ScrollViewer` events and then feed that update back into an animated programmatic `ScrollTo`. Competing native and programmatic scroll paths could cause runaway scrolling or leave the selected item visibly off-center. This change: - suppresses only the exact `Position`/`CurrentItem` mapper callbacks produced by native scrolling and handler-originated collection reconciliation, while preserving application-driven nested updates and nesting the suppression state safely; - lets newer user/native input supersede active corrective recentering instead of swallowing it as part of the previous request; - treats a routed mouse-wheel event as immediate user intent, removing the timing window that could leave stale collection state active before `ViewChanging`; - uses the geometrically nearest visible item for both logical selection and terminal centering, with the native center index as a fallback while containers are realized; - defers terminal geometry until Windows has completed virtualized layout and versions queued work so newer input, application scrolling, collection updates, and disconnects invalidate stale callbacks; - recenters when Windows scrolling settles for centered `Mandatory` and `MandatorySingle` snap points and bounds corrective attempts when native coercion rejects a requested center; - preserves `KeepScrollOffset` reconciliation and synchronous application `Position` or `CurrentItem` overrides during collection updates, including reentrant `PositionChanged` updates; - validates native collection projection after layout, follows `Items.VectorChanged` progress without resetting the bounded retry budget, realizes offscreen override targets natively, and issues one final centered MAUI scroll; - reuses one retry timer within a handler connection, then stops, detaches, and releases it on disconnect so reconnect uses the new dispatcher; - makes repeated native `ScrollViewer` discovery idempotent and detaches routed/native handlers symmetrically on replacement and disconnect; - maps looped physical indexes to logical indexes, realizes looped targets in the central physical cycle, and keeps final centering in that high physical range without exposing `CenterMode` across asynchronous work; - resets all transient scroll, timer, pointer-input, initialization, loop-facade, and native collection subscription state across superseding input and handler disconnect/reconnect; - applies forward tie-breaking against the true minimum distance so the 1 px tolerance cannot compound; and - clamps target offsets at scroll boundaries. The fix is limited to the Windows CarouselView implementation. Native `None`, Start, and End snap behavior remains owned by WinUI. ### Validation Validated with the issue's linked reproduction at commit `cee7aee936214bbe7fa2a06ffec7d6d14876bb8c`, built against the final PR sources. Rapid forward wheel bursts, delayed tail input, and rapid reverse input each remained responsive and settled within 1 px of the viewport center. The Windows `CarouselView` device-test category now contains 45 tests. Added or strengthened coverage includes repeated `ScrollViewer` discovery, immediate wheel supersession, reentrant `PositionChanged` collection overrides, monotonic native-projection retry budgets, deterministic looped high-cycle realization/final centering, nested native-scroll attribution, retry-timer reuse, and disconnect/reconnect cleanup. - **controlled previous production handler:** 41 passed, 4 failed; the failures discriminate nested scroll attribution, retry-timer reuse, disconnect cleanup (including initialization and loop-facade state), and the redundant-layout collection path; - **test-first timer lifecycle check:** 44 passed, 1 failed before disconnect disposal; 45 passed, 0 failed after the fix; - **final local unpackaged Windows CarouselView suite:** 45 passed, 0 failed; - **final local real-packaged Windows CarouselView suite:** 45 passed, 0 failed; - **exact linked reproduction:** all three wheel scenarios settled within 1 px; and - **independent MAUI expert review:** found the cross-disconnect timer ownership issue above; re-review after its test-first fix was clean with no remaining findings. All test counts come from authoritative XML read after the test process exited. #### Before fix The card remains visibly displaced after scrolling (measured approximately 112 px from the viewport center). https://github.com/user-attachments/assets/ae6c8f6b-648e-4927-9591-4af9c27bd874 #### After fix The same interaction remains responsive and settles with the card centered (runtime validation tolerance was <=1 px). https://github.com/user-attachments/assets/1ea9a740-770c-4783-85c9-183e75cb9d96 ### Testing Requested @LaoR-UA, thank you for the reproduction and manual feedback. When CI publishes artifacts for this PR, could you please [try the resulting build](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) with your original project and let us know whether mouse-wheel scrolling now behaves correctly on your setup? ### Issues Fixed Fixes #35621 ---------
…e members (#36444) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ### Description of Change XAML Source Generation emitted direct member access for binding paths, so a `null` intermediate (for example, `{Binding A.B.C.Text}` where `A` or `B` is null at runtime) threw `NullReferenceException`. This diverged from runtime and XamlC bindings, which tolerate null intermediates. The root cause was that the generator based null-conditional access on nullable reference-type annotations. Those annotations are not enforced at runtime: a reference declared non-nullable can still be `null`. This change: - Uses runtime nullability for member, array-index, and indexer path parts, and propagates the resulting nullable type through generated getters, setters, handlers, and `TypedBinding<,>` arguments. - Keeps two-way bindings able to write `null` through null-tolerant paths. Reference-type endpoints assign with the null-forgiving operator to remain warning-free; non-nullable value types retain the existing null guard. - Handles value-type property and indexer intermediates with read-modify-write generation. The setter updates a captured copy and assigns it back through each property/indexer in reverse order, avoiding both CS1612 and silently dropped writes. - Identifies array elements from the receiver type. Array elements and value-type fields remain direct lvalues and are not captured. Getter output, before and after: ```csharp // A, B, and C are non-nullable-declared reference types getter: source => (source.A.B.C.Text, true), getter: source => (source.A?.B?.C?.Text, true), ``` The first hop remains non-conditional (`source.Foo`, not `source?.Foo`) because `TypedBinding.ApplyCore` invokes the getter only with a non-null source. Non-nullable value-type endpoints retain their `?? default` fallback so their binding property types do not change. ### Tests - Updated exact generated-code expectations for compiled bindings, indexers, and Maui13856. - Added coverage for non-nullable-declared reference intermediates. - Added coverage proving two-way paths still write `null`. - Added setter coverage for value-type properties, indexers, arrays, fields, and nested reverse-order copy-back. ### Issues Fixed Fixes #36313 --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: simonrozsival <374616+simonrozsival@users.noreply.github.com> Co-authored-by: Jonathan Peppers <jonathan.peppers@microsoft.com> Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Co-authored-by: Simon Rozsival <simon@rozsival.com> Copilot-Session: 10f057bb-7603-49db-aaf3-707c0cf0ddff
…eservation Causing Phantom Scroll Range (#37765) > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! On iOS, a ScrollView configured with SafeAreaEdges="Container" incorrectly reserves the safe area twice, resulting in an additional phantom scroll range. When the content is smaller than the viewport, the ScrollView becomes unnecessarily scrollable. The extra scrollable area corresponds exactly to the combined safe-area insets (for example, 82 pt on an iPhone 11: 48 pt for the status bar and 34 pt for the home indicator). When the content is taller than the viewport, the same issue causes an unnecessary dead over-scroll space at the end of the content. The issue occurs because MauiScrollView.CrossPlatformArrange always pads the scroll content's measured size by the safe-area thickness when ContentInsetAdjustmentBehavior is not Automatic, without checking whether UIKit has already reserved the same space through AdjustedContentInset. As a result, when SafeAreaEdges="Container" is set and the native inset is active, the safe area is accounted for twice—once by UIKit and once by the manual padding. This inflates the content size beyond its actual bounds and produces a phantom scrollable range, even when the content should not be scrollable. The fix narrows the manual-padding condition so that it applies only when the native inset is genuinely inactive—that is, when SystemAdjustedContentInset is zero or ContentInsetAdjustmentBehavior is Never. In all other cases, UIKit's own inset is trusted to reserve the safe area, and the content size is left unchanged. This removes the double reservation for SafeAreaEdges="Container" while preserving the existing None and Automaticbehaviors. Tested the behavior in the following platforms. - [x] iOS - [x] Android - [ ] Mac - [ ] Windows Fixes #36800 |Before Fix|After Fix| |--|--| <video src="https://github.com/user-attachments/assets/19c064e4-4622-4d1d-992c-340a56fb948f"> |<video src="https://github.com/user-attachments/assets/57fa7cae-6e95-4573-885d-8f2979750f38">| --------- Co-authored-by: Jakub Florkowski <42434498+kubaflo@users.noreply.github.com>
…37648) <!-- Please keep the note below for people who find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment whether this change resolves your issue. Thank you! This pull request addresses issues with the accuracy of the `CanGoBack` and `CanGoForward` properties in the Windows WebView handler, ensuring that navigation state is correctly reflected and not stale. It also adds a regression test to prevent future issues with navigation history. ### Description of Change **Fixes and improvements to WebView navigation state:** * Updated the logic in `WebViewHandler.Windows.cs` to check `CoreWebView2.CanGoBack` and `CoreWebView2.CanGoForward` instead of relying solely on the WebView2 control properties, which could become stale and cause incorrect navigation behavior. * Enhanced the `UpdateCanGoBackForward` extension method in `WebViewExtensions.cs` to prefer the `CoreWebView2` navigation state for `CanGoBack` and `CanGoForward`, falling back to the control's properties only when necessary. **Testing and regression prevention:** * Added a new test, `CanGoBackIsFalseAfterReturningToFirstPage`, to verify that `CanGoBack` is set to false after navigating back to the first page, preventing regressions related to navigation history. <!-- Enter description of the fix in this section --> ### Issues Fixed <!-- Please make sure that there is a bug logged for the issue being fixed. The bug should describe the problem and how to reproduce it. --> Fixes #37534 ### Tested the behavior in the following platforms - [x] Windows - [ ] Android - [ ] iOS - [ ] Mac | Before Issue Fix | After Issue Fix | |----------|----------| | <video src="https://github.com/user-attachments/assets/c6c4e68b-21ac-49cd-ad96-3f628c889674"> | <video src="https://github.com/user-attachments/assets/1a0fcee7-32d4-42a6-8003-25b89087e580"> | <!-- Are you targeting main? All PRs should target the main branch unless otherwise noted. --> ---------
…est (#37267) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ### Issue Details - On iOS, an Image does not scale up on the unconstrained axis when only HeightRequest or WidthRequest is set—the unconstrained axis remains capped at its native size. This is most visible with HorizontalStackLayout + HeightRequest and VerticalStackLayout + WidthRequest. The reverse combinations can appear to work because the other axis is large enough to mask the same issue. On Android, the Image scales correctly with HeightRequest and WidthRequest in all cases. ### Root Cause - In SizeThatFitsImage (iOS), the scale factor for ScaleAspectFit images was calculated as Math.Min(imageWidth, widthConstraint) / imageWidth. This could never exceed 1 (since it always divides the image's own size by itself once the constraint is larger), so an image could shrink to fit a smaller space but could never grow beyond its native size, even when an explicit HeightRequest or WidthRequest requested a larger size, regardless of StackLayout orientation. ### Description of Change - Updated SizeThatFitsImage in ImageViewExtensions.cs to accept flags indicating whether width and height constraints are explicit, and to allow images to scale up to requested sizes when either is set, instead of capping at native size. - Modified GetDesiredSizeFromHandler in ViewHandlerExtensions.iOS.cs to pass explicitness flags to SizeThatFitsImage, ensuring correct sizing behavior for images with explicit size requests. ### Issues Fixed Fixes #12879 ### Validated the behaviour in the following platforms - [ ] Windows - [ ] Android - [x] iOS - [x] Mac ### Output | Before | After | ----------|----------| | <img src="https://github.com/user-attachments/assets/c592756b-d87f-40dd-9073-0a4e03add828"> | <img src="https://github.com/user-attachments/assets/c884d1d2-a048-44ee-b1d9-ac59b9c29daf"> |
…37772) <!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> The issue was caused by a small view moved off-screen with TranslationY for a full-screen Shell navigation animation. This incorrectly preserved the top safe-area inset, creating the unwanted gap in the bottom sheet. https://github.com/dotnet/maui/blob/19a188896c0e518c0d201db181f67166c740724d/src/Core/src/Platform/Android/SafeAreaExtensions.cs#L175 On Android, moving a view outside the screen using TranslationY incorrectly adds top padding to the layout. <!-- Enter description of the fix in this section --> Updated Android vertical animation detection to treat only full-screen views as Shell navigation transitions. Smaller translated controls, are excluded so they no longer receive incorrect top safe-area padding. <!-- Please make sure that there is a bug logged for the issue being fixed. The bug should describe the problem and how to reproduce it. --> Fixes #37418 <!-- Are you targeting main? All PRs should target the main branch unless otherwise noted. --> **Tested the behavior in the following platforms.** - [x] Android - [ ] Windows - [x] iOS - [ ] Mac | Before | After | |---------|--------| | **Android**<br> <img src="https://github.com/user-attachments/assets/9a17e25d-4b59-4d33-9b22-014bb504e3a0" width="300" height="600"> | **Android**<br> <img src="https://github.com/user-attachments/assets/aef1bf14-dca6-411f-94e4-c473ac3b5d0c" width="300" height="600"> | --------- Co-authored-by: Jakub Florkowski <42434498+kubaflo@users.noreply.github.com>
<!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ### Description of Change On Windows, WinUI's initial focus routing can select the first focusable descendant of a `ScrollViewer`. When a page opens with an `Entry` inside a scrollable MAUI `ScrollView`, that can focus the `Entry` and raise its `Focused` event without user input. The Windows handler now makes the native `ScrollViewer` a **transient** tab stop from WinUI's `Loading` event, giving the load-time focus pass a non-content target. A queued callback restores the original native, styled, locally customized, or bound `IsTabStop` state after load, so the ScrollViewer does not become a permanent keyboard or Narrator stop. A low-priority fail-safe queued from `Loading` also restores the transient state if the ScrollViewer leaves the native visual tree before either `Loaded` or `Unloaded` fires. The normal `Loaded` callback supersedes that fail-safe through a generation guard and restores on the next dispatcher turn. The temporary value is represented by an owned binding: if an app or mapper writes the native property before restore, that write replaces the binding and wins. Generation plus platform-view identity checks prevent stale callbacks from mutating a disconnected or replaced handler. Cleanup and restoration intentionally happen before `base.DisconnectHandler`, while the platform view and handler ownership are still valid; all lifecycle events are unsubscribed before base teardown. The shared Windows unfocus path preserves the original binding/local/style/default ownership of `IsTabStop`, so an unfocus operation during the temporary window cannot convert the transient value into a permanent local tab stop. Bindings are detached before the temporary `false` write so TwoWay sources are not mutated, then the original binding object is reinstated. No public API is added or changed. ### What NOT to Do - Do not make the internal `ContentPanel` a tab stop: it creates an invisible, unannounced keyboard stop. - Do not leave `ScrollViewer.IsTabStop=true` permanently: that changes steady-state tab order and accessibility for every Windows ScrollView. - Do not set `AllowFocusOnInteraction=false`: empirical testing showed that it also prevents legitimate pointer focus of child Entries. - Do not restore a hardcoded `IsTabStop` value: doing so destroys style, binding, and custom handler/mapper ownership. - Do not write a temporary dependency-property value while a TwoWay binding is attached: that pushes the temporary value into the source. - Do not use a normal-priority fail-safe from `Loading`: it can run before WinUI reaches `Loaded`, restoring too early and reintroducing automatic Entry focus. The fail-safe must remain low priority. - Do not synchronously restore when the low-priority `Loading` enqueue fails: empirical testing showed that removing the transient target during `Loading` recreates automatic Entry focus. Dispatcher shutdown remains covered by synchronous handler disconnect cleanup. - Do not cancel `GettingFocus` to identify automatic focus: WinUI reports both automatic and legitimate app requests as programmatic focus, so that signal cannot distinguish them safely. ### Issues Fixed Fixes #31039 ### Validation - Windows Controls `ScrollView` device tests with the fix: **26 passed, 0 failed**. Coverage includes direct transient activation, lifecycle ordering through `Loaded`, negative startup focus with a preceding Button and two sibling ScrollViews, native/default/local/style/OneWay/TwoWay ownership, binding detachment, TwoWay source and binding identity, later native writes, unfocus during the transient window, explicit focus, disconnect/reconnect, unload/reload, stale callbacks, native focused-element state, rooted Tab and Shift+Tab navigation, and removal from the native visual tree during `Loading` before `Loaded`/`Unloaded`. - Controlled sensitivity with only production `Loading` activation disabled: **20 passed, 6 failed**. The discriminating failures are startup focus, preceding-control/two-ScrollView startup focus, navigation reload, transient ordering, reverse navigation from the startup ScrollViewer, and custom local-value restoration. - Windows Controls `Entry` device tests: **54 passed, 0 failed, 4 skipped**. A non-ScrollView regression test verifies that programmatic Unfocus preserves style ownership and tracks a later style replacement. - The issue author's exact attached sample was rebuilt against the unchanged production implementation represented by head `21d3526a1b` and automated with UI Automation plus real pointer/keyboard input: - startup focus is the native ScrollViewer UIA `Pane`, exposed as a control/content element; no Entry focus and no alert; - clicking a normal Entry focuses it; - Tab advances to the next Entry; - Shift+Tab returns to the previous Entry; - clicking an `InputTransparent` Entry does not raise the first Entry's focus alert. - Independent MAUI-specialist and adversarial lifecycle reviews found no remaining high-confidence defect after the added fail-safe and discriminating coverage. - Optional device build 1565839 contained one unrelated MacCatalyst CarouselView leak failure; its osx.26 Helix job passed. Optional UI build 1565837 had broad cross-platform baseline failures also present on adjacent main builds. Required main build 1565836 passed. ### Empirical Proof **Before — untouched attached sample (MAUI 9.0.14):** https://github.com/user-attachments/assets/fc1c44f3-e385-4808-9f00-9694b83e127f **After — exact sample rebuilt against the transient fix:** https://github.com/user-attachments/assets/af84a6c5-97e1-4ddd-a89f-3730748b8cf2 @Kamalesh-Periyasamy, once the updated PR artifacts are available, please try them with your original reproduction and let us know whether this resolves the issue for you. --------- Copilot-Session: bcd06486-88bb-4458-ad38-55bf1be162f5
…37111) This pull request makes several improvements to the Entry control test pages and their supporting view models, focusing on expanding test coverage, improving UI accessibility, and enhancing code maintainability. The most significant changes include adding new bindable properties (such as `BackgroundColor`, `Opacity`, and `WidthRequest`), updating event handler logic for better testability, and refining the ViewModel with new helpers and a reset method. Additionally, UI elements have been updated for consistency and accessibility. **Feature and UI enhancements:** * Added bindable properties `BackgroundColor`, `Opacity`, and `WidthRequest` to the Entry controls and ViewModel, allowing these properties to be set and tested from the UI (`EntryControlPage.xaml`, `Material3_EntryControlPage.xaml`, `EntryViewModel.cs`). [[1]](diffhunk://#diff-14e7f146267aafe278aab3e4cec14f9fc100e09ae21886569c33bffba87cff28R42-R44) [[2]](diffhunk://#diff-f5e3ee56e4135c8dfd05cfce9bf234d413b52c8b6ce864a4ba0fca1ad004cc75R42-R44) [[3]](diffhunk://#diff-3f677ed4c454a245e3e82416c1a86b24aa0ade96b3b809d4cbedd7bc75534536L28-R32) [[4]](diffhunk://#diff-3f677ed4c454a245e3e82416c1a86b24aa0ade96b3b809d4cbedd7bc75534536R180-R213) * Added new labels to display the current keyboard type and return type in the UI, and updated the ViewModel to provide these values (`EntryControlPage.xaml`, `EntryViewModel.cs`). [[1]](diffhunk://#diff-14e7f146267aafe278aab3e4cec14f9fc100e09ae21886569c33bffba87cff28L100-R131) [[2]](diffhunk://#diff-3f677ed4c454a245e3e82416c1a86b24aa0ade96b3b809d4cbedd7bc75534536L124-R136) [[3]](diffhunk://#diff-3f677ed4c454a245e3e82416c1a86b24aa0ade96b3b809d4cbedd7bc75534536R180-R213) **Event handler and logic improvements:** * Updated event handlers to use `TextChanged` events for properties like cursor position, selection length, max length, width request, opacity, and height request, improving testability and code clarity (`EntryControlPage.xaml.cs`, `EntryOptionsPage.xaml.cs`). [[1]](diffhunk://#diff-976ce0c4d44779d336f56a5b66c3d1d02d6b59783311ee99efb4f5d1eb58317fL39-L54) [[2]](diffhunk://#diff-07ad3578095d6b7e4ef419d6921a7d43b5319bfd2970f669cb006118d1677de7L124-R134) [[3]](diffhunk://#diff-07ad3578095d6b7e4ef419d6921a7d43b5319bfd2970f669cb006118d1677de7L259-R318) * Refactored color selection logic for text and placeholder colors to use `AutomationId` instead of background color, increasing reliability in UI tests (`EntryOptionsPage.xaml.cs`). [[1]](diffhunk://#diff-07ad3578095d6b7e4ef419d6921a7d43b5319bfd2970f669cb006118d1677de7L26-R31) [[2]](diffhunk://#diff-07ad3578095d6b7e4ef419d6921a7d43b5319bfd2970f669cb006118d1677de7L50-R60) * Added a new reset method to the ViewModel to restore all properties to their default values, and updated the navigation logic to call this method (`EntryViewModel.cs`, `EntryControlPage.xaml.cs`). [[1]](diffhunk://#diff-3f677ed4c454a245e3e82416c1a86b24aa0ade96b3b809d4cbedd7bc75534536R312-R348) [[2]](diffhunk://#diff-976ce0c4d44779d336f56a5b66c3d1d02d6b59783311ee99efb4f5d1eb58317fL39-L54) **UI and accessibility updates:** * Added `AutomationId` values to key UI elements for improved automated testing and accessibility (`EntryControlPage.xaml`, `Material3_EntryControlPage.xaml`). [[1]](diffhunk://#diff-14e7f146267aafe278aab3e4cec14f9fc100e09ae21886569c33bffba87cff28R10-L13) [[2]](diffhunk://#diff-f5e3ee56e4135c8dfd05cfce9bf234d413b52c8b6ce864a4ba0fca1ad004cc75L8-L20) * Adjusted font sizes for consistency and improved label clarity, and reorganized UI elements for better structure and accessibility (`EntryControlPage.xaml`). [[1]](diffhunk://#diff-14e7f146267aafe278aab3e4cec14f9fc100e09ae21886569c33bffba87cff28L70-R78) [[2]](diffhunk://#diff-14e7f146267aafe278aab3e4cec14f9fc100e09ae21886569c33bffba87cff28L100-R131) These changes collectively improve the testability, maintainability, and accessibility of the Entry control test pages. Issue Identified: - #34611 - #29805 --------- Co-authored-by: Jakub Florkowski <kubaflo123@gmail.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
<!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ## Description Enables `AllowDrop` on the Windows BlazorWebView's underlying WinUI `WebView2` so external files dragged from Explorer can reach HTML drop targets. This addresses the Windows external-file-drop portion of #2205. Native in-page HTML element and image dragging remains blocked by upstream WinUI/WebView2 behavior and is outside the scope of this change. A cross-host repro and compatibility matrix are available at https://github.com/danroth27/BlazorHybridDragDrop. ## Testing - Added a Windows device test that verifies the created platform WebView2 has `AllowDrop` enabled. - Windows BlazorWebView device tests: 18 passed, 4 skipped, 0 failed. Fixes #37903 Copilot-Session: 6ecbe107-8703-4352-a1c6-e4f722cb9b28
<!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! <!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> ### Issue Details When ScrollView.Orientation="Horizontal" on Android, the content unexpectedly scrolls a few pixels vertically too, even though only horizontal scrolling was requested. ### Root Cause Android's outer scroll container calculates vertical scroll range using its inner horizontal-scroll child's height vs. its own padded content area. MAUI's code sized that inner child using the full (unpadded) outer height, leaving a small leftover gap equal to the padding — causing phantom vertical scroll. ### Description of Change In MauiScrollView.cs , OnMeasure / OnLayout now subtract PaddingTop/Bottom/Left/Right when sizing the inner horizontal scroll view, and offset its layout position by PaddingLeft/Top . This makes the inner view exactly match the true content area, eliminating the leftover scroll range. Validated the behavior in the following platforms - [x] Android - [x] Windows - [x] iOS - [x] Mac ### Issues Fixed Fixes #37335 ### Output ScreenShot |Before|After| |--|--| | <video src="https://github.com/user-attachments/assets/677494c4-4e09-4e1b-af46-eeb48a3c2f7a" >| <video src="https://github.com/user-attachments/assets/0180fcf3-6c7e-482b-bad0-7893e0838aa9">|
<!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ### Description of Change Marks `MauiWinUIApplication.Services` and `MauiWinUIApplication.Application` obsolete with actionable guidance to use `IPlatformApplication.Current` instead. This aligns Windows with the existing Android, iOS/MacCatalyst, and Tizen API surface and removes the overdue .NET 9 TODOs. ### Rationale PR #16803 moved framework internals away from concrete native application hosts to support embedding scenarios and originally deprecated these properties. PR #17667 deferred the Windows annotations because the WinUI XAML generator surfaced obsolete warnings from generated accessors. The current WinUI XAML generator now wraps generated obsolete-property accesses in `#pragma warning disable 0618`, so default projects no longer receive those warnings. Handwritten consumers still receive the intended migration warning. No `PublicAPI` baseline update is required because the property signatures are unchanged and obsolete attributes are not represented by the current baseline format. ### Validation - Built `Core.csproj` for `net10.0-windows10.0.19041.0` - Built `Core.csproj` for `net10.0-windows10.0.20348.0` - Rebuilt the Windows Sandbox app and confirmed generated accessors produce no `CS0618` or `RS0030` warnings --------- Co-authored-by: Jakub Florkowski <42434498+kubaflo@users.noreply.github.com>
<!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ## Summary - use the type-safe `Bundle.GetParcelable` overload for `WebAuthenticatorIntermediateActivity` on Android API 33 and newer - preserve the obsolete overload for Android API 21-32 - document why `ActivationState` must retain generic `Bundle.Get` access to preserve arbitrary value stringification - remove obsolete and platform warning suppressions where the typed overload makes them unnecessary ## Validation - `dotnet build src\Essentials\src\Essentials.csproj -f net10.0-android36.0 --no-restore --nologo -v:minimal` — 0 warnings, 0 errors - `dotnet build src\Core\src\Core.csproj -f net10.0-android36.0 --no-restore --nologo -v:minimal` — succeeded with only the existing Gradle Java 8 source/target warnings - `pwsh .github\skills\run-device-tests\scripts\Run-DeviceTests.ps1 -Project Essentials -Platform android -BuildOnly` — succeeded and produced the signed APK No Android emulator was available on the Windows validation host, so API 21-32 and API 33+ Activity recreation paths were not runtime-executed. The implementation follows the existing `IntermediateActivity` compatibility pattern. --------- Co-authored-by: Jakub Florkowski <42434498+kubaflo@users.noreply.github.com>
<!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ## Description Fixes #37429. On iOS, grouped `CollectionView` used the flattened leaf-item count to control `EmptyView` visibility. Removing the final item from an existing group therefore displayed `EmptyView` over a group that still existed. Grouped sources now use the outer `GroupCount`, so `EmptyView` remains hidden while any group exists and appears only after the final group is removed. The fix applies to both iOS handler generations: the legacy `CollectionViewHandler` and current `CollectionViewHandler2`. Each handler also retains a separate leaf-item emptiness signal so measurement and cache behavior is not coupled to group-level `EmptyView` state. This is the iOS-specific split of closed #37439, which maintainers requested be separated by platform. It intentionally contains no Android changes. ## Tests Added iOS device tests for both handlers using eventual assertions. They cover the reported populated-group-to-empty-group transition, verify that `EmptyView` does not overlay the remaining empty group after its final item is removed, verify that removing the final group shows `EmptyView`, and verify that adding an empty group hides it again. The iOS Debug device-test bundle builds successfully on Xcode 26.4. Local simulator execution could not complete because the installed XHarness 9 CLI cannot enumerate Xcode 26.4 simulators (exit code 71). ---------
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
1 similar comment
This comment has been minimized.
This comment has been minimized.
|
CI has now independently run the focused iOS regression suite at The pipeline is still running, so this is not an overall green-CI claim. The completed Windows failures have matching target-branch evidence; the two iOS CollectionView1 failures are missing |
|
Follow-up CI attribution at
The combined runtime command was Keeping this draft and the servicing patch unchanged while the remaining jobs finish. No new public APIs or unrelated CI fixes added. |
|
CI update for unchanged head The separate Android New persistent Android CollectionView/Label/ScrollView and macOS CollectionView failures match exact-base build 1640775, including the same missing snapshots and percentage differences. One additional Android |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
The All three requested AzDO pipelines have now finished: maui-pr passed; device/UI pipelines are not green. The final Android CoreCLR Shell leg hit its 240-minute limit after a run with 132 passed / 221 failed, mostly a disposed-IApp setup cascade. Exact-base UI build 1640775 log 8303 independently shows that setup signature and the same two app-not-running diagnostics; that does not prove an identical underlying crash. Newly completed macOS Layout, Editor/shadow and ScrollView persistent failures also match the exact base. The macOS Entry |
1ef1b30 to
4606786
Compare
This comment has been minimized.
This comment has been minimized.
|
Azure Pipelines will not run the associated pipelines, because the pull request was updated after the run command was issued. Review the pull request again and issue a new run command. |
|
@kubaflo Azure rejected the run request, and no new AzDO builds have queued. The head is still |
4606786 to
f6b9897
Compare



Note
Are you waiting for the changes in this PR to be merged?
It would be very helpful if you could test the resulting artifacts from this PR and let us know in a comment if this change resolves your issue. Thank you!
Description of Change
Smaller servicing replacement for #38067, following kubaflo's review. This deliberately retains the original PR's
inflight/currenttarget. No new public APIs, API-file changes, or changes to the Core assembly.On iOS 26, a compatibility ListView/TableView inside a non-Shell NavigationPage layout can remain below the large navigation bar without participating in UIKit's large-title scrolling. Its table controller can also lack page-controller containment, preventing native safe-area inheritance.
For a single eligible compatibility list, arrange its branch beneath the translucent bar in one managed layout pass, establish missing table-controller containment, and register the native scroll view for UIKit's top inset handling. Keep sibling overlays and footers in their ordinary safe bounds. Restore the previous native registration/inset behavior and release owned containment when the host is removed, reparented, or disconnected. Also remeasure the large-title bar after its navigation controller changes size while absent, covering rotation beneath a full-screen cover.
Scope is intentionally narrow: iOS 26+, non-Catalyst, root ContentPage layouts with implicit Container top safe area, a visible translucent large-title compatibility NavigationPage, and exactly one supported ListView/TableView. Explicit safe areas, fixed headers, multiple lists, top margins/padding, fixed/non-fill list sizing, opaque/hidden bars, and Never titles are excluded. CollectionView and ScrollView behavior is not changed. This is not a general safe-area redesign.
Native-only post-layout frame changes and two-pass safe/edge-to-edge arrangement were discarded: compatibility renderers restore managed bounds, and the intermediate safe layout can clamp the scroll offset and break title restoration.
Validation
On an iPhone 17 Pro simulator running iOS 26.5:
HEADLESS=true pwsh .github/scripts/BuildAndRunHostApp.ps1 -Platform ios -DeviceUdid 7B88EF5A-5797-465A-A193-EB0ABF44F55C -TestFilter 'FullyQualifiedName~Issue33037NonShell'— 15 passed. Covers reporter/nested/table collapse and restoration, short reverse gestures, stable list geometry, expanded/collapsed cover+rotation re-entry, excluded layouts, dynamic explicit-safe-area ownership, and live list transfer from a cached page.HEADLESS=true DEVICE_UDID=7B88EF5A-5797-465A-A193-EB0ABF44F55C pwsh .github/skills/verify-tests-fail-without-fix/scripts/verify-tests-fail.ps1 -Platform ios -TestType UITest -PRNumber local-33037 -BaseBranch be754b5e9a1e242d54f159d2537778b7c185e51d -TestFilter 'FullyQualifiedName~Issue33037NonShell.LargeTitleCollapsesAndRestoresWithoutMovingTheList' -RequireFullVerification— VERIFICATION PASSED: all three cases fail on the frozen baseline (title stays 42 points instead of collapsing below 30), and all three pass with the fix.dotnet test src/Controls/tests/Core.UnitTests/Controls.Core.UnitTests.csproj --filter 'FullyQualifiedName~LayoutTests' --no-restore— 394 passed.dotnet build src/Controls/src/Core/Controls.Core.csproj -f net10.0-maccatalyst26.0 -p:ValidateXcodeVersion=false --no-restore— succeeded, 0 warnings/errors.Local iOS runs additionally exported
XCODE_XCCONFIG_FILEpointing to a localIPHONEOS_DEPLOYMENT_TARGET = 15.0override andCustomAfterMicrosoftCommonTargetspointing to a local target addingLinkerArgumentvalues-rpathand/usr/lib/swift. These compensate for the installed Xcode 27.1/.NET iOS SDK combination; neither override is part of this PR. An earlier A/B attempt was blocked by this toolchain's deployment-target/Swift-runtime startup errors, not treated as reproduction evidence. The final runs above executed the tests successfully. The runner also emits a separate device-log collection warning after successful test completion.Independent source reviewers identified and helped resolve ownership/teardown issues; a separate runtime reviewer exercised nested compact/expanded cover+rotation re-entry and restoration. All final consultations reported no blocking findings. This is bounded regression evidence, not a guarantee for untested configurations; older iOS versions, physical devices, Android, and Windows were not functionally run. Runtime screenshots and a short recording will be attached in a comment.
Issues Fixed
Fixes #33037
Supersedes #38067 for the remaining non-Shell compatibility-list scenario.