Skip to content

Fixed HideSoftInputOnTapped="True" on one page permanently affects all other pages if NavigatedFrom is never fired - #36238

Merged
kubaflo merged 7 commits into
dotnet:inflight/currentfrom
KarthikRajaKalaimani:fix-35890
Jul 18, 2026
Merged

kubaflo merged 7 commits into
dotnet:inflight/currentfrom
KarthikRajaKalaimani:fix-35890

Conversation

@KarthikRajaKalaimani

@KarthikRajaKalaimani KarthikRajaKalaimani commented Jun 30, 2026 •

Copy link
Copy Markdown
Contributor

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!

Issue Details:

HideSoftInputOnTapped="True" on one page permanently affects all other pages

Root Cause:

HideSoftInputOnTappedChangedManager maintained an internal List _contentPages to track which pages had HideSoftInputOnTapped="True" enabled. Pages were added to this list when NavigatedTo fired on them, and removed when NavigatedFrom fired. The FeatureEnabled property iterated this list to decide whether the global tap-to-dismiss keyboard behavior should be active. The critical flaw was that this entire cleanup mechanism depended solely on NavigatedFrom firing. In the specific scenario described in issue #35890 — where a ShellContent is hidden by setting IsVisible=false followed by an absolute GoToAsync("///Route") call — the Shell framework skips firing NavigatedFrom on the outgoing page entirely. As a result, the login page remained permanently registered in _contentPages with HideSoftInputOnTapped=true, keeping FeatureEnabled=true globally. Every subsequent page in the app — even pages with HideSoftInputOnTapped=false — had the keyboard dismissed on tap, because the stale login page entry in the list kept overriding the correct behavior.

Description of Change:

The fix eliminates _contentPages and the event-subscription model entirely. Instead of maintaining a tracked list of pages, FeatureEnabled is now computed on-demand by walking the Element.Parent chain upward from the currently focused input view (FocusedView). A new static helper GetEnclosingPage(IView?) traverses the parent chain until it finds the enclosing ContentPage, then reads HideSoftInputOnTapped and HasNavigatedTo directly from that live page instance. Since the result is computed from the actual visual tree at the moment of the query, there is no cache and no stale state possible — if the page is gone from the tree, FocusedView becomes null and FeatureEnabled returns false automatically. This also resolves a secondary regression that existed in an earlier Unloaded-based fix: if a page was re-shown after being hidden, the old approach would permanently break for that page instance because HasNavigatedTo was never reset. With the parent-chain walk, the live property values are always used, so re-show scenarios work correctly without any special handling. The UpdatePage method, which previously managed list mutations and event subscriptions, is now a single line that re-evaluates the tap watcher setup. The Android-specific OnWindowDispatchedTouch handler is similarly simplified — instead of looping over the list, it calls GetEnclosingPage(FocusedView) once and acts on the result directly.

Previous behavior: FeatureEnabled returned true if any registered page had
HideSoftInputOnTapped set to true — even if that page was no longer the active/visible
page (this was the root cause of #35890, the "sticky" keyboard-dismissal bug). In effect, one
page's setting could leak and affect the keyboard behavior on unrelated pages.

New behavior: FeatureEnabled now only checks the page enclosing the currently focused
view. Only the active page's HideSoftInputOnTapped value applies.
**Tested the behavior in the following platforms: **

  • Android
  • Windows
  • iOS
  • Mac

Reference:

N/A

Issues Fixed:

Fixes #35890

Screenshots

Before After
Before_35890.mov
After_35890.mov

KarthikRajaKalaimani and others added 6 commits June 16, 2026 09:40
Co-Authored-By: Copilot <223556219+Copilot@users.noreply.github.com>
Co-Authored-By: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions

Copy link
Copy Markdown
Contributor

🚀 Dogfood this PR with:

⚠️ WARNING: Do not do this without first carefully reviewing the code of this PR to satisfy yourself it is safe.

curl -fsSL https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.sh | bash -s -- 36238

Or

  • Run remotely in PowerShell:
iex "& { $(irm https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.ps1) } 36238"

@dotnet-policy-service dotnet-policy-service Bot added the community ✨ Community Contribution label Jun 30, 2026
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Hey there @@KarthikRajaKalaimani! Thank you so much for your PR! Someone from the team will get assigned to your PR shortly and we'll get it reviewed.

@dotnet-policy-service dotnet-policy-service Bot added the partner/syncfusion Issues / PR's with Syncfusion collaboration label Jun 30, 2026
@KarthikRajaKalaimani KarthikRajaKalaimani changed the title [WIP] Fixed HideSoftInputOnTapped="True" on one page permanently affects all other pages if NavigatedFrom is never fired Fixed HideSoftInputOnTapped="True" on one page permanently affects all other pages if NavigatedFrom is never fired Jul 2, 2026
@kubaflo

This comment has been minimized.

@github-actions github-actions Bot added the s/agent-review-in-progress AI review is currently running for this PR label Jul 5, 2026

@MauiBot MauiBot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Expert Review — 3 findings

See inline comments for details.

// that was cached when the view became focused. This preserves the
// original behavior where the feature remains enabled until the view
// explicitly loses focus.
var page = GetEnclosingPage(FocusedView) ?? FocusedEnclosingPage;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔍 AI-Generated Review (multi-model)

[major] Logic and Correctness / Regression Prevention — FeatureEnabled falls back to FocusedEnclosingPage (the page cached when the view became focused) whenever the live Parent walk from FocusedView returns null. This reintroduces a variant of the exact bug this PR fixes: if the focused input on the outgoing page is detached (e.g. ShellContent.IsVisible = false + absolute GoToAsync, per the Issue35890 repro) before its native IsFocused=false update runs, SendNavigatedFrom never fires, so the cached page's HasNavigatedTo stays true forever. Until some other input view anywhere in the app receives focus (which clears _focusedView/_focusedViewEnclosingPage), a tap on the new destination page is evaluated against the stale cached page's HideSoftInputOnTapped/HasNavigatedTo, not the destination page's. Consider dropping the fallback (accepting that a genuinely-detached view disables the feature) or gating the fallback on the cached page still being the currently active page/window, rather than only on the view's Parent chain being non-null.

// hiding the ShellContent via IsVisible=false and navigating with an absolute path
// does NOT fire NavigatedFrom on the outgoing page.
_loginShellContent.IsVisible = false;
_ = Current.GoToAsync("///HomePage35890");

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔍 AI-Generated Review (multi-model)

[moderate] Regression Prevention and Test Coverage — This repro (and the paired UI test) logs in by tapping LoginButton directly, without ever focusing UsernameEntry first. That means NavigateToHome() never exercises the scenario where the manager's _focusedViewEnclosingPage fallback is actually populated with the outgoing (Login) page at the moment of navigation — the exact path this PR's fix (HideSoftInputOnTappedChangedManager.Platform.cs) added to handle. Add a variant that taps UsernameEntry (to give it focus and populate the cache) immediately before calling NavigateToHome(), then assert HomePage35890's HideSoftInputOnTapped=false is still honored on the very first tap after arriving — this is the scenario most likely to reveal a stale-cache regression.

// Step 1: Log in from the LoginPage (HideSoftInputOnTapped = True), unless a previous
// test in this fixture has already done so.
// This triggers NavigatedTo on the LoginPage, which registers it in
// HideSoftInputOnTappedChangedManager._contentPages.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔍 AI-Generated Review (multi-model)

[minor] Stale comment — This comment says logging in "registers it in HideSoftInputOnTappedChangedManager._contentPages", but this same PR removes the _contentPages field entirely (see HideSoftInputOnTappedChangedManager.cs diff) in favor of the focused-view/_focusedViewEnclosingPage model. The comment describes the pre-fix implementation detail and will confuse future maintainers reading the post-fix code; please update it to describe the current (focused-view-based) mechanism or drop the implementation-detail reference.

@MauiBot MauiBot added s/agent-gate-failed AI could not verify tests catch the bug s/agent-fix-pr-picked AI could not beat the PR fix - PR is the best among all candidates s/agent-reviewed PR was reviewed by AI agent workflow (full 4-phase review) labels Jul 5, 2026
MauiBot

This comment was marked as outdated.

@MauiBot MauiBot removed the s/agent-review-in-progress AI review is currently running for this PR label Jul 5, 2026

@kubaflo kubaflo left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please check the ai's suggestions?

@kubaflo

This comment has been minimized.

@github-actions github-actions Bot added the s/agent-review-in-progress AI review is currently running for this PR label Jul 8, 2026

@MauiBot MauiBot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Expert Review — 1 findings

See inline comments for details.

// that was cached when the view became focused. This preserves the
// original behavior where the feature remains enabled until the view
// explicitly loses focus.
var page = GetEnclosingPage(FocusedView) ?? FocusedEnclosingPage;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔍 AI-Generated Review (multi-model)

[major] Handler lifecycle — Falling back to the cached focused page keeps FeatureEnabled true after the focused input has been detached from the live tree. In the issue scenario, if an Entry on the HideSoftInputOnTapped=true page is focused before Shell hides/navigates away without LostFocus/NavigatedFrom, the old tap watcher can remain active until another input receives focus, so tapping a non-input control on a HideSoftInputOnTapped=false destination can still be processed using the stale page. Please clear the tracked focus when the focused view is detached/windowless, or gate dispatch on the current visible page instead of the cached page.

MauiBot

This comment was marked as outdated.

@MauiBot MauiBot removed the s/agent-review-in-progress AI review is currently running for this PR label Jul 8, 2026
@kubaflo

This comment has been minimized.

@github-actions github-actions Bot added the s/agent-review-in-progress AI review is currently running for this PR label Jul 14, 2026

@MauiBot MauiBot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Expert Review — 2 findings

See inline comments for details.

// that was cached when the view became focused. This preserves the
// original behavior where the feature remains enabled until the view
// explicitly loses focus.
var page = GetEnclosingPage(FocusedView) ?? FocusedEnclosingPage;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔍 AI-Generated Review (multi-model)

[major] Logic and Correctness — Falling back to the cached FocusedEnclosingPage keeps using the old page after the focused input is detached without a focus-lost event. In the issue scenario, if the login page keeps focus and Shell hides/navigates it without NavigatedFrom, HasNavigatedTo remains true, so FeatureEnabled stays true and Android can still dispatch taps through the stale page until another input gets focus. This reintroduces the cross-page persistence the PR is trying to remove; prefer requiring the focused view to resolve to a live enclosing page (or otherwise clearing this cache on detach/navigation).

// The login action hides the ShellContent (IsVisible=false) and navigates
// via absolute GoToAsync — which does NOT fire NavigatedFrom on the LoginPage.
// Step 2: Verify we are on the HomePage (HideSoftInputOnTapped = False).
EnsureOnHomePage();

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔍 AI-Generated Review (multi-model)

[major] Regression Prevention and Test Coverage — This test navigates away from the login page without first focusing UsernameEntry, so it does not cover the stale focused-input path introduced by the cached-page fallback. The old global-list bug is exercised after HomeEntry receives focus, but a login entry that remains focused while NavigatedFrom is skipped can still leave the previous page controlling tap dismissal. Please focus the login entry/show the keyboard before tapping LoginButton (or add a separate test) so the regression test fails for that case.

@MauiBot MauiBot added s/agent-gate-passed AI verified tests catch the bug (fail without fix, pass with fix) and removed s/agent-gate-failed AI could not verify tests catch the bug labels Jul 14, 2026

@MauiBot MauiBot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AI Review Summary

@KarthikRajaKalaimani — new AI review results are available based on this last commit: 91a3d6b. To request a fresh review after new comments or commits, comment /review rerun.

Gate Passed Confidence Low Platform Android


🗂️ Review Sessions — click to expand
🚦 Gate — Test Before & After Fix

Gate Result: ✅ PASSED

Platform: ANDROID · Base: main · Merge base: 0395a53b

Test Without Fix (expect FAIL) With Fix (expect PASS)
🖥️ Issue35890 Issue35890 ✅ FAIL — 2339s ✅ PASS — 1708s
🔴 Without fix — 🖥️ Issue35890: FAIL ✅ · 2339s

(truncated to last 15,000 chars)

ome/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.dll
  Controls.BindingSourceGen -> /home/vsts/work/1/s/artifacts/bin/Controls.BindingSourceGen/Debug/netstandard2.0/Microsoft.Maui.Controls.BindingSourceGen.dll
  ##vso[build.updatebuildnumber]10.0.100-ci+azdo.14656745
  ##vso[build.updatebuildnumber]10.0.100-ci+azdo.14656745
  Maps -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Maps.dll
  Controls.Core -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Controls.dll
  ##vso[build.updatebuildnumber]10.0.100-ci+azdo.14656745
  ##vso[build.updatebuildnumber]10.0.100-ci+azdo.14656745
  ##vso[build.updatebuildnumber]10.0.100-ci+azdo.14656745
  Controls.Foldable -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Controls.Foldable.dll
  Controls.Xaml -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Controls.Xaml.dll
  Microsoft.AspNetCore.Components.WebView.Maui -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.AspNetCore.Components.WebView.Maui.dll
  ##vso[build.updatebuildnumber]10.0.100-ci+azdo.14656745
  Controls.Maps -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Controls.Maps.dll

Build succeeded.
    0 Warning(s)
    0 Error(s)

Time Elapsed 00:08:17.46
Broadcasting: Intent { act=android.intent.action.CLOSE_SYSTEM_DIALOGS flg=0x400000 }
Broadcast completed: result=0
Broadcasting: Intent { act=android.intent.action.CLOSE_SYSTEM_DIALOGS flg=0x400000 }
Broadcast completed: result=0
Broadcasting: Intent { act=android.intent.action.CLOSE_SYSTEM_DIALOGS flg=0x400000 }
Broadcast completed: result=0
Starting: Intent { act=android.settings.SETTINGS }
Broadcasting: Intent { act=android.intent.action.CLOSE_SYSTEM_DIALOGS flg=0x400000 }
Broadcast completed: result=0
  Determining projects to restore...
  Restored /home/vsts/work/1/s/src/Controls/tests/CustomAttributes/Controls.CustomAttributes.csproj (in 1.28 sec).
  Restored /home/vsts/work/1/s/src/TestUtils/src/VisualTestUtils/VisualTestUtils.csproj (in 4 ms).
  Restored /home/vsts/work/1/s/src/TestUtils/src/VisualTestUtils.MagickNet/VisualTestUtils.MagickNet.csproj (in 4.5 sec).
  Restored /home/vsts/work/1/s/src/Controls/tests/TestCases.Android.Tests/Controls.TestCases.Android.Tests.csproj (in 5.95 sec).
  Restored /home/vsts/work/1/s/src/TestUtils/src/UITest.Core/UITest.Core.csproj (in 2 ms).
  Restored /home/vsts/work/1/s/src/TestUtils/src/UITest.Appium/UITest.Appium.csproj (in 3 ms).
  Restored /home/vsts/work/1/s/src/TestUtils/src/UITest.NUnit/UITest.NUnit.csproj (in 237 ms).
  Restored /home/vsts/work/1/s/src/TestUtils/src/UITest.Analyzers/UITest.Analyzers.csproj (in 6.2 sec).
  5 of 13 projects are up-to-date for restore.
  ##vso[build.updatebuildnumber]10.0.100-ci+azdo.14656745
  Graphics -> /home/vsts/work/1/s/artifacts/bin/Graphics/Debug/net10.0/Microsoft.Maui.Graphics.dll
  Controls.CustomAttributes -> /home/vsts/work/1/s/artifacts/bin/Controls.CustomAttributes/Debug/net10.0/Controls.CustomAttributes.dll
  ##vso[build.updatebuildnumber]10.0.100-ci+azdo.14656745
  Essentials -> /home/vsts/work/1/s/artifacts/bin/Essentials/Debug/net10.0/Microsoft.Maui.Essentials.dll
  ##vso[build.updatebuildnumber]10.0.100-ci+azdo.14656745
  Core -> /home/vsts/work/1/s/artifacts/bin/Core/Debug/net10.0/Microsoft.Maui.dll
  Controls.BindingSourceGen -> /home/vsts/work/1/s/artifacts/bin/Controls.BindingSourceGen/Debug/netstandard2.0/Microsoft.Maui.Controls.BindingSourceGen.dll
  ##vso[build.updatebuildnumber]10.0.100-ci+azdo.14656745
  Controls.Core -> /home/vsts/work/1/s/artifacts/bin/Controls.Core/Debug/net10.0/Microsoft.Maui.Controls.dll
  VisualTestUtils -> /home/vsts/work/1/s/artifacts/bin/VisualTestUtils/Debug/netstandard2.0/VisualTestUtils.dll
  UITest.Core -> /home/vsts/work/1/s/artifacts/bin/UITest.Core/Debug/net10.0/UITest.Core.dll
  UITest.Appium -> /home/vsts/work/1/s/artifacts/bin/UITest.Appium/Debug/net10.0/UITest.Appium.dll
  UITest.NUnit -> /home/vsts/work/1/s/artifacts/bin/UITest.NUnit/Debug/net10.0/UITest.NUnit.dll
  VisualTestUtils.MagickNet -> /home/vsts/work/1/s/artifacts/bin/VisualTestUtils.MagickNet/Debug/netstandard2.0/VisualTestUtils.MagickNet.dll
  UITest.Analyzers -> /home/vsts/work/1/s/artifacts/bin/UITest.Analyzers/Debug/netstandard2.0/UITest.Analyzers.dll
  Controls.TestCases.Android.Tests -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.Android.Tests/Debug/net10.0/Controls.TestCases.Android.Tests.dll
Test run for /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.Android.Tests/Debug/net10.0/Controls.TestCases.Android.Tests.dll (.NETCoreApp,Version=v10.0)
VSTest version 18.0.1 (x64)

Starting test execution, please wait...
A total of 1 test files matched the specified pattern.
NUnit Adapter 4.5.0.0: Test execution started
Running selected tests in /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.Android.Tests/Debug/net10.0/Controls.TestCases.Android.Tests.dll
   NUnit3TestExecutor discovered 2 of 2 NUnit test cases using Current Discovery mode, Non-Explicit run
>>>>> 07/14/2026 21:41:17 FixtureSetup for Issue35890(Android)
>>>>> 07/14/2026 21:41:21 HideSoftInputOnTappedDoesNotPersistAfterShellContentHiddenWithoutNavigatedFrom Start
>>>>> 07/14/2026 21:41:34 HideSoftInputOnTappedDoesNotPersistAfterShellContentHiddenWithoutNavigatedFrom Stop
>>>>> 07/14/2026 21:41:35 Log types: logcat, bugreport, server
  Failed HideSoftInputOnTappedDoesNotPersistAfterShellContentHiddenWithoutNavigatedFrom [14 s]
  Error Message:
     Keyboard should remain visible when HideSoftInputOnTapped=False is set on the current page. The stale LoginPage registration in HideSoftInputOnTappedChangedManager must have been cleaned up.
Assert.That(App.IsKeyboardShown(), Is.True)
  Expected: True
  But was:  False

  Stack Trace:
     at Microsoft.Maui.TestCases.Tests.Issues.Issue35890.HideSoftInputOnTappedDoesNotPersistAfterShellContentHiddenWithoutNavigatedFrom() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue35890.cs:line 68

1)    at Microsoft.Maui.TestCases.Tests.Issues.Issue35890.HideSoftInputOnTappedDoesNotPersistAfterShellContentHiddenWithoutNavigatedFrom() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue35890.cs:line 68


>>>>> 07/14/2026 21:41:36 HideSoftInputOnTappedRespectsPerPageSemanticsWithClassicPushNavigation Start
>>>>> 07/14/2026 21:41:45 HideSoftInputOnTappedRespectsPerPageSemanticsWithClassicPushNavigation Stop
>>>>> 07/14/2026 21:41:45 Log types: logcat, bugreport, server
WebDriverException: OpenQA.Selenium.StaleElementReferenceException: Cached elements 'By.accessibilityId: Navigate up' do not exist in DOM anymore; For documentation on this error, please visit: https://www.selenium.dev/documentation/webdriver/troubleshooting/errors#stale-element-reference-exception
   at OpenQA.Selenium.WebDriver.UnpackAndThrowOnError(Response errorResponse, String commandToExecute)
   at OpenQA.Selenium.WebDriver.ExecuteAsync(String driverCommandToExecute, Dictionary`2 parameters)
   at OpenQA.Selenium.WebDriver.InternalExecute(String driverCommandToExecute, Dictionary`2 parameters)
   at OpenQA.Selenium.WebElement.Execute(String commandToExecute, Dictionary`2 parameters)
   at OpenQA.Selenium.WebElement.Click()
   at UITest.Appium.AppiumMouseActions.ClickElement(AppiumElement element) in /_/src/TestUtils/src/UITest.Appium/Actions/AppiumMouseActions.cs:line 106

  Failed HideSoftInputOnTappedRespectsPerPageSemanticsWithClassicPushNavigation [10 s]
  Error Message:
   OpenQA.Selenium.StaleElementReferenceException : Cached elements 'By.accessibilityId: Navigate up' do not exist in DOM anymore; For documentation on this error, please visit: https://www.selenium.dev/documentation/webdriver/troubleshooting/errors#stale-element-reference-exception

  1)   Keyboard should remain visible when tapping outside the Entry on a page with HideSoftInputOnTapped = False, even though the previous page in the navigation stack had HideSoftInputOnTapped = True.
Assert.That(App.IsKeyboardShown(), Is.True)
  Expected: True
  But was:  False


  Stack Trace:
     at OpenQA.Selenium.WebDriver.UnpackAndThrowOnError(Response errorResponse, String commandToExecute)
   at OpenQA.Selenium.WebDriver.ExecuteAsync(String driverCommandToExecute, Dictionary`2 parameters)
   at OpenQA.Selenium.WebDriver.InternalExecute(String driverCommandToExecute, Dictionary`2 parameters)
   at OpenQA.Selenium.WebElement.Execute(String commandToExecute, Dictionary`2 parameters)
   at OpenQA.Selenium.Appium.AppiumElement.Execute(String commandName, Dictionary`2 parameters)
   at OpenQA.Selenium.Appium.AppiumElement._GetAttribute(String attributeName)
   at OpenQA.Selenium.Appium.AppiumElement.<>c__DisplayClass21_0.<GetAttribute>b__0()
   at OpenQA.Selenium.Appium.AppiumElement.CacheValue(String key, Func`1 getter)
   at OpenQA.Selenium.Appium.AppiumElement.GetAttribute(String attributeName)
   at UITest.Appium.AppiumMouseActions.ElementToClickablePoint(AppiumElement element) in /_/src/TestUtils/src/UITest.Appium/Actions/AppiumMouseActions.cs:line 230
   at UITest.Appium.AppiumMouseActions.<ClickElement>g__ProcessException|13_0(<>c__DisplayClass13_0&) in /_/src/TestUtils/src/UITest.Appium/Actions/AppiumMouseActions.cs:line 136
   at UITest.Appium.AppiumMouseActions.ClickElement(AppiumElement element) in /_/src/TestUtils/src/UITest.Appium/Actions/AppiumMouseActions.cs:line 117
   at UITest.Appium.AppiumMouseActions.Click(IDictionary`2 parameters) in /_/src/TestUtils/src/UITest.Appium/Actions/AppiumMouseActions.cs:line 63
   at UITest.Appium.AppiumMouseActions.Execute(String commandName, IDictionary`2 parameters) in /_/src/TestUtils/src/UITest.Appium/Actions/AppiumMouseActions.cs:line 45
   at UITest.Appium.AppiumCommandExecutor.Execute(String commandName, IDictionary`2 parameters) in /_/src/TestUtils/src/UITest.Appium/Actions/AppiumCommandExecutor.cs:line 20
   at UITest.Appium.HelperExtensions.Click(IUIElement element) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 412
   at Microsoft.Maui.TestCases.Tests.UtilExtensions.Back(UITestContextBase testBase) in /_/src/Controls/tests/TestCases.Shared.Tests/UtilExtensions.cs:line 18
   at Microsoft.Maui.TestCases.Tests.Issues.Issue35890.HideSoftInputOnTappedRespectsPerPageSemanticsWithClassicPushNavigation() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue35890.cs:line 121
   at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
   at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)
1)    at Microsoft.Maui.TestCases.Tests.Issues.Issue35890.HideSoftInputOnTappedRespectsPerPageSemanticsWithClassicPushNavigation() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue35890.cs:line 110

2)    at OpenQA.Selenium.WebDriver.UnpackAndThrowOnError(Response errorResponse, String commandToExecute)
   at OpenQA.Selenium.WebDriver.ExecuteAsync(String driverCommandToExecute, Dictionary`2 parameters)
   at OpenQA.Selenium.WebDriver.InternalExecute(String driverCommandToExecute, Dictionary`2 parameters)
   at OpenQA.Selenium.WebElement.Execute(String commandToExecute, Dictionary`2 parameters)
   at OpenQA.Selenium.Appium.AppiumElement.Execute(String commandName, Dictionary`2 parameters)
   at OpenQA.Selenium.Appium.AppiumElement._GetAttribute(String attributeName)
   at OpenQA.Selenium.Appium.AppiumElement.<>c__DisplayClass21_0.<GetAttribute>b__0()
   at OpenQA.Selenium.Appium.AppiumElement.CacheValue(String key, Func`1 getter)
   at OpenQA.Selenium.Appium.AppiumElement.GetAttribute(String attributeName)
   at UITest.Appium.AppiumMouseActions.ElementToClickablePoint(AppiumElement element) in /_/src/TestUtils/src/UITest.Appium/Actions/AppiumMouseActions.cs:line 230
   at UITest.Appium.AppiumMouseActions.<ClickElement>g__ProcessException|13_0(<>c__DisplayClass13_0&) in /_/src/TestUtils/src/UITest.Appium/Actions/AppiumMouseActions.cs:line 136
   at UITest.Appium.AppiumMouseActions.ClickElement(AppiumElement element) in /_/src/TestUtils/src/UITest.Appium/Actions/AppiumMouseActions.cs:line 117
   at UITest.Appium.AppiumMouseActions.Click(IDictionary`2 parameters) in /_/src/TestUtils/src/UITest.Appium/Actions/AppiumMouseActions.cs:line 63
   at UITest.Appium.AppiumMouseActions.Execute(String commandName, IDictionary`2 parameters) in /_/src/TestUtils/src/UITest.Appium/Actions/AppiumMouseActions.cs:line 45
   at UITest.Appium.AppiumCommandExecutor.Execute(String commandName, IDictionary`2 parameters) in /_/src/TestUtils/src/UITest.Appium/Actions/AppiumCommandExecutor.cs:line 20
   at UITest.Appium.HelperExtensions.Click(IUIElement element) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 412
   at Microsoft.Maui.TestCases.Tests.UtilExtensions.Back(UITestContextBase testBase) in /_/src/Controls/tests/TestCases.Shared.Tests/UtilExtensions.cs:line 18
   at Microsoft.Maui.TestCases.Tests.Issues.Issue35890.HideSoftInputOnTappedRespectsPerPageSemanticsWithClassicPushNavigation() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue35890.cs:line 121
   at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
   at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)

  Standard Output Messages:
 WebDriverException: OpenQA.Selenium.StaleElementReferenceException: Cached elements 'By.accessibilityId: Navigate up' do not exist in DOM anymore; For documentation on this error, please visit: https://www.selenium.dev/documentation/webdriver/troubleshooting/errors#stale-element-reference-exception
    at OpenQA.Selenium.WebDriver.UnpackAndThrowOnError(Response errorResponse, String commandToExecute)
    at OpenQA.Selenium.WebDriver.ExecuteAsync(String driverCommandToExecute, Dictionary`2 parameters)
    at OpenQA.Selenium.WebDriver.InternalExecute(String driverCommandToExecute, Dictionary`2 parameters)
    at OpenQA.Selenium.WebElement.Execute(String commandToExecute, Dictionary`2 parameters)
    at OpenQA.Selenium.WebElement.Click()
    at UITest.Appium.AppiumMouseActions.ClickElement(AppiumElement element) in /_/src/TestUtils/src/UITest.Appium/Actions/AppiumMouseActions.cs:line 106


NUnit Adapter 4.5.0.0: Test execution complete
[xUnit.net 00:00:00.00] xUnit.net VSTest Adapter v2.8.2+699d445a1a (64-bit .NET 10.0.0)
[xUnit.net 00:00:00.12]   Discovering: Controls.TestCases.Android.Tests
[xUnit.net 00:00:00.53]   Discovered:  Controls.TestCases.Android.Tests
Results File: /home/vsts/work/1/s/CustomAgentLogsTmp/UITests/TestResults/Issue35890.trx

Test Run Failed.
Total tests: 2
     Failed: 2
 Total time: 50.9928 Seconds
>>> TRX_RESULT_FILE: /home/vsts/work/1/s/CustomAgentLogsTmp/UITests/TestResults/Issue35890.trx

🟢 With fix — 🖥️ Issue35890: PASS ✅ · 1708s

(truncated to last 15,000 chars)

 completed: result=0
Starting: Intent { act=android.settings.SETTINGS }
Broadcasting: Intent { act=android.intent.action.CLOSE_SYSTEM_DIALOGS flg=0x400000 }
Broadcast completed: result=0
  Determining projects to restore...
  All projects are up-to-date for restore.
  Controls.CustomAttributes -> /home/vsts/work/1/s/artifacts/bin/Controls.CustomAttributes/Debug/net10.0/Controls.CustomAttributes.dll
  ##vso[build.updatebuildnumber]10.0.100-ci+azdo.14656745
  Graphics -> /home/vsts/work/1/s/artifacts/bin/Graphics/Debug/net10.0/Microsoft.Maui.Graphics.dll
  ##vso[build.updatebuildnumber]10.0.100-ci+azdo.14656745
  Essentials -> /home/vsts/work/1/s/artifacts/bin/Essentials/Debug/net10.0/Microsoft.Maui.Essentials.dll
  ##vso[build.updatebuildnumber]10.0.100-ci+azdo.14656745
  Core -> /home/vsts/work/1/s/artifacts/bin/Core/Debug/net10.0/Microsoft.Maui.dll
  Controls.BindingSourceGen -> /home/vsts/work/1/s/artifacts/bin/Controls.BindingSourceGen/Debug/netstandard2.0/Microsoft.Maui.Controls.BindingSourceGen.dll
  ##vso[build.updatebuildnumber]10.0.100-ci+azdo.14656745
  Controls.Core -> /home/vsts/work/1/s/artifacts/bin/Controls.Core/Debug/net10.0/Microsoft.Maui.Controls.dll
  UITest.Core -> /home/vsts/work/1/s/artifacts/bin/UITest.Core/Debug/net10.0/UITest.Core.dll
  VisualTestUtils -> /home/vsts/work/1/s/artifacts/bin/VisualTestUtils/Debug/netstandard2.0/VisualTestUtils.dll
  UITest.Appium -> /home/vsts/work/1/s/artifacts/bin/UITest.Appium/Debug/net10.0/UITest.Appium.dll
  UITest.NUnit -> /home/vsts/work/1/s/artifacts/bin/UITest.NUnit/Debug/net10.0/UITest.NUnit.dll
  VisualTestUtils.MagickNet -> /home/vsts/work/1/s/artifacts/bin/VisualTestUtils.MagickNet/Debug/netstandard2.0/VisualTestUtils.MagickNet.dll
  UITest.Analyzers -> /home/vsts/work/1/s/artifacts/bin/UITest.Analyzers/Debug/netstandard2.0/UITest.Analyzers.dll
  Controls.TestCases.Android.Tests -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.Android.Tests/Debug/net10.0/Controls.TestCases.Android.Tests.dll
Test run for /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.Android.Tests/Debug/net10.0/Controls.TestCases.Android.Tests.dll (.NETCoreApp,Version=v10.0)
VSTest version 18.0.1 (x64)

Starting test execution, please wait...
A total of 1 test files matched the specified pattern.
NUnit Adapter 4.5.0.0: Test execution started
Running selected tests in /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.Android.Tests/Debug/net10.0/Controls.TestCases.Android.Tests.dll
   NUnit3TestExecutor discovered 2 of 2 NUnit test cases using Current Discovery mode, Non-Explicit run
>>>>> 07/14/2026 22:00:15 FixtureSetup for Issue35890(Android)
>>>>> 07/14/2026 22:00:17 HideSoftInputOnTappedDoesNotPersistAfterShellContentHiddenWithoutNavigatedFrom Start
>>>>> 07/14/2026 22:00:28 HideSoftInputOnTappedDoesNotPersistAfterShellContentHiddenWithoutNavigatedFrom Stop
  Passed HideSoftInputOnTappedDoesNotPersistAfterShellContentHiddenWithoutNavigatedFrom [11 s]
>>>>> 07/14/2026 22:00:29 HideSoftInputOnTappedRespectsPerPageSemanticsWithClassicPushNavigation Start
>>>>> 07/14/2026 22:00:37 HideSoftInputOnTappedRespectsPerPageSemanticsWithClassicPushNavigation Stop
>>>>> 07/14/2026 22:00:37 Log types: logcat, bugreport, server
WebDriverException: OpenQA.Selenium.StaleElementReferenceException: Cached elements 'By.accessibilityId: Navigate up' do not exist in DOM anymore; For documentation on this error, please visit: https://www.selenium.dev/documentation/webdriver/troubleshooting/errors#stale-element-reference-exception
   at OpenQA.Selenium.WebDriver.UnpackAndThrowOnError(Response errorResponse, String commandToExecute)
   at OpenQA.Selenium.WebDriver.ExecuteAsync(String driverCommandToExecute, Dictionary`2 parameters)
   at OpenQA.Selenium.WebDriver.InternalExecute(String driverCommandToExecute, Dictionary`2 parameters)
   at OpenQA.Selenium.WebElement.Execute(String commandToExecute, Dictionary`2 parameters)
   at OpenQA.Selenium.WebElement.Click()
   at UITest.Appium.AppiumMouseActions.ClickElement(AppiumElement element) in /_/src/TestUtils/src/UITest.Appium/Actions/AppiumMouseActions.cs:line 106

  Failed HideSoftInputOnTappedRespectsPerPageSemanticsWithClassicPushNavigation [9 s]
  Error Message:
   OpenQA.Selenium.StaleElementReferenceException : Cached elements 'By.accessibilityId: Navigate up' do not exist in DOM anymore; For documentation on this error, please visit: https://www.selenium.dev/documentation/webdriver/troubleshooting/errors#stale-element-reference-exception
  Stack Trace:
     at OpenQA.Selenium.WebDriver.UnpackAndThrowOnError(Response errorResponse, String commandToExecute)
   at OpenQA.Selenium.WebDriver.ExecuteAsync(String driverCommandToExecute, Dictionary`2 parameters)
   at OpenQA.Selenium.WebDriver.InternalExecute(String driverCommandToExecute, Dictionary`2 parameters)
   at OpenQA.Selenium.WebElement.Execute(String commandToExecute, Dictionary`2 parameters)
   at OpenQA.Selenium.Appium.AppiumElement.Execute(String commandName, Dictionary`2 parameters)
   at OpenQA.Selenium.Appium.AppiumElement._GetAttribute(String attributeName)
   at OpenQA.Selenium.Appium.AppiumElement.<>c__DisplayClass21_0.<GetAttribute>b__0()
   at OpenQA.Selenium.Appium.AppiumElement.CacheValue(String key, Func`1 getter)
   at OpenQA.Selenium.Appium.AppiumElement.GetAttribute(String attributeName)
   at UITest.Appium.AppiumMouseActions.ElementToClickablePoint(AppiumElement element) in /_/src/TestUtils/src/UITest.Appium/Actions/AppiumMouseActions.cs:line 230
   at UITest.Appium.AppiumMouseActions.<ClickElement>g__ProcessException|13_0(<>c__DisplayClass13_0&) in /_/src/TestUtils/src/UITest.Appium/Actions/AppiumMouseActions.cs:line 136
   at UITest.Appium.AppiumMouseActions.ClickElement(AppiumElement element) in /_/src/TestUtils/src/UITest.Appium/Actions/AppiumMouseActions.cs:line 117
   at UITest.Appium.AppiumMouseActions.Click(IDictionary`2 parameters) in /_/src/TestUtils/src/UITest.Appium/Actions/AppiumMouseActions.cs:line 63
   at UITest.Appium.AppiumMouseActions.Execute(String commandName, IDictionary`2 parameters) in /_/src/TestUtils/src/UITest.Appium/Actions/AppiumMouseActions.cs:line 45
   at UITest.Appium.AppiumCommandExecutor.Execute(String commandName, IDictionary`2 parameters) in /_/src/TestUtils/src/UITest.Appium/Actions/AppiumCommandExecutor.cs:line 20
   at UITest.Appium.HelperExtensions.Click(IUIElement element) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 412
   at Microsoft.Maui.TestCases.Tests.UtilExtensions.Back(UITestContextBase testBase) in /_/src/Controls/tests/TestCases.Shared.Tests/UtilExtensions.cs:line 18
   at Microsoft.Maui.TestCases.Tests.Issues.Issue35890.HideSoftInputOnTappedRespectsPerPageSemanticsWithClassicPushNavigation() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue35890.cs:line 121
   at Microsoft.Maui.TestCases.Tests.Issues.Issue35890.HideSoftInputOnTappedRespectsPerPageSemanticsWithClassicPushNavigation() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue35890.cs:line 82
   at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
   at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)

  Standard Output Messages:
 WebDriverException: OpenQA.Selenium.StaleElementReferenceException: Cached elements 'By.accessibilityId: Navigate up' do not exist in DOM anymore; For documentation on this error, please visit: https://www.selenium.dev/documentation/webdriver/troubleshooting/errors#stale-element-reference-exception
    at OpenQA.Selenium.WebDriver.UnpackAndThrowOnError(Response errorResponse, String commandToExecute)
    at OpenQA.Selenium.WebDriver.ExecuteAsync(String driverCommandToExecute, Dictionary`2 parameters)
    at OpenQA.Selenium.WebDriver.InternalExecute(String driverCommandToExecute, Dictionary`2 parameters)
    at OpenQA.Selenium.WebElement.Execute(String commandToExecute, Dictionary`2 parameters)
    at OpenQA.Selenium.WebElement.Click()
    at UITest.Appium.AppiumMouseActions.ClickElement(AppiumElement element) in /_/src/TestUtils/src/UITest.Appium/Actions/AppiumMouseActions.cs:line 106


NUnit Adapter 4.5.0.0: Test execution complete
[xUnit.net 00:00:00.00] xUnit.net VSTest Adapter v2.8.2+699d445a1a (64-bit .NET 10.0.0)
[xUnit.net 00:00:00.13]   Discovering: Controls.TestCases.Android.Tests
[xUnit.net 00:00:00.53]   Discovered:  Controls.TestCases.Android.Tests
Results File: /home/vsts/work/1/s/CustomAgentLogsTmp/UITests/TestResults/Issue35890.trx

Total tests: 2
     Passed: 1
     Failed: 1
Test Run Failed.
 Total time: 34.0839 Seconds
>>> TRX_RESULT_FILE: /home/vsts/work/1/s/CustomAgentLogsTmp/UITests/TestResults/Issue35890.trx
Test run for /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.Android.Tests/Debug/net10.0/Controls.TestCases.Android.Tests.dll (.NETCoreApp,Version=v10.0)
VSTest version 18.0.1 (x64)

Starting test execution, please wait...
A total of 1 test files matched the specified pattern.
NUnit Adapter 4.5.0.0: Test execution started
Running selected tests in /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.Android.Tests/Debug/net10.0/Controls.TestCases.Android.Tests.dll
   NUnit3TestExecutor discovered 1 of 1 NUnit test cases using Current Discovery mode, Non-Explicit run
>>>>> 07/14/2026 22:00:52 FixtureSetup for Issue35890(Android)
>>>>> 07/14/2026 22:00:53 HideSoftInputOnTappedRespectsPerPageSemanticsWithClassicPushNavigation Start
>>>>> 07/14/2026 22:01:10 HideSoftInputOnTappedRespectsPerPageSemanticsWithClassicPushNavigation Stop
>>>>> 07/14/2026 22:01:10 Log types: logcat, bugreport, server
WebDriverException: OpenQA.Selenium.StaleElementReferenceException: Cached elements 'By.accessibilityId: Navigate up' do not exist in DOM anymore; For documentation on this error, please visit: https://www.selenium.dev/documentation/webdriver/troubleshooting/errors#stale-element-reference-exception
   at OpenQA.Selenium.WebDriver.UnpackAndThrowOnError(Response errorResponse, String commandToExecute)
   at OpenQA.Selenium.WebDriver.ExecuteAsync(String driverCommandToExecute, Dictionary`2 parameters)
   at OpenQA.Selenium.WebDriver.InternalExecute(String driverCommandToExecute, Dictionary`2 parameters)
   at OpenQA.Selenium.WebElement.Execute(String commandToExecute, Dictionary`2 parameters)
   at OpenQA.Selenium.WebElement.Click()
   at UITest.Appium.AppiumMouseActions.ClickElement(AppiumElement element) in /_/src/TestUtils/src/UITest.Appium/Actions/AppiumMouseActions.cs:line 106

  Failed HideSoftInputOnTappedRespectsPerPageSemanticsWithClassicPushNavigation [16 s]
  Error Message:
   OpenQA.Selenium.StaleElementReferenceException : Cached elements 'By.accessibilityId: Navigate up' do not exist in DOM anymore; For documentation on this error, please visit: https://www.selenium.dev/documentation/webdriver/troubleshooting/errors#stale-element-reference-exception
  Stack Trace:
     at OpenQA.Selenium.WebDriver.UnpackAndThrowOnError(Response errorResponse, String commandToExecute)
   at OpenQA.Selenium.WebDriver.ExecuteAsync(String driverCommandToExecute, Dictionary`2 parameters)
   at OpenQA.Selenium.WebDriver.InternalExecute(String driverCommandToExecute, Dictionary`2 parameters)
   at OpenQA.Selenium.WebElement.Execute(String commandToExecute, Dictionary`2 parameters)
   at OpenQA.Selenium.Appium.AppiumElement.Execute(String commandName, Dictionary`2 parameters)
   at OpenQA.Selenium.Appium.AppiumElement._GetAttribute(String attributeName)
   at OpenQA.Selenium.Appium.AppiumElement.<>c__DisplayClass21_0.<GetAttribute>b__0()
   at OpenQA.Selenium.Appium.AppiumElement.CacheValue(String key, Func`1 getter)
   at OpenQA.Selenium.Appium.AppiumElement.GetAttribute(String attributeName)
   at UITest.Appium.AppiumMouseActions.ElementToClickablePoint(AppiumElement element) in /_/src/TestUtils/src/UITest.Appium/Actions/AppiumMouseActions.cs:line 230
   at UITest.Appium.AppiumMouseActions.<ClickElement>g__ProcessException|13_0(<>c__DisplayClass13_0&) in /_/src/TestUtils/src/UITest.Appium/Actions/AppiumMouseActions.cs:line 136
   at UITest.Appium.AppiumMouseActions.ClickElement(AppiumElement element) in /_/src/TestUtils/src/UITest.Appium/Actions/AppiumMouseActions.cs:line 117
   at UITest.Appium.AppiumMouseActions.Click(IDictionary`2 parameters) in /_/src/TestUtils/src/UITest.Appium/Actions/AppiumMouseActions.cs:line 63
   at UITest.Appium.AppiumMouseActions.Execute(String commandName, IDictionary`2 parameters) in /_/src/TestUtils/src/UITest.Appium/Actions/AppiumMouseActions.cs:line 45
   at UITest.Appium.AppiumCommandExecutor.Execute(String commandName, IDictionary`2 parameters) in /_/src/TestUtils/src/UITest.Appium/Actions/AppiumCommandExecutor.cs:line 20
   at UITest.Appium.HelperExtensions.Click(IUIElement element) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 412
   at Microsoft.Maui.TestCases.Tests.UtilExtensions.Back(UITestContextBase testBase) in /_/src/Controls/tests/TestCases.Shared.Tests/UtilExtensions.cs:line 18
   at Microsoft.Maui.TestCases.Tests.Issues.Issue35890.HideSoftInputOnTappedRespectsPerPageSemanticsWithClassicPushNavigation() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue35890.cs:line 121
   at Microsoft.Maui.TestCases.Tests.Issues.Issue35890.HideSoftInputOnTappedRespectsPerPageSemanticsWithClassicPushNavigation() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue35890.cs:line 82
   at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
   at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)

  Standard Output Messages:
 WebDriverException: OpenQA.Selenium.StaleElementReferenceException: Cached elements 'By.accessibilityId: Navigate up' do not exist in DOM anymore; For documentation on this error, please visit: https://www.selenium.dev/documentation/webdriver/troubleshooting/errors#stale-element-reference-exception
    at OpenQA.Selenium.WebDriver.UnpackAndThrowOnError(Response errorResponse, String commandToExecute)
    at OpenQA.Selenium.WebDriver.ExecuteAsync(String driverCommandToExecute, Dictionary`2 parameters)
    at OpenQA.Selenium.WebDriver.InternalExecute(String driverCommandToExecute, Dictionary`2 parameters)
    at OpenQA.Selenium.WebElement.Execute(String commandToExecute, Dictionary`2 parameters)
    at OpenQA.Selenium.WebElement.Click()
    at UITest.Appium.AppiumMouseActions.ClickElement(AppiumElement element) in /_/src/TestUtils/src/UITest.Appium/Actions/AppiumMouseActions.cs:line 106


NUnit Adapter 4.5.0.0: Test execution complete
[xUnit.net 00:00:00.00] xUnit.net VSTest Adapter v2.8.2+699d445a1a (64-bit .NET 10.0.0)
[xUnit.net 00:00:00.14]   Discovering: Controls.TestCases.Android.Tests
[xUnit.net 00:00:00.59]   Discovered:  Controls.TestCases.Android.Tests
Results File: /home/vsts/work/1/s/CustomAgentLogsTmp/UITests/TestResults/retry-Issue35890.trx

Test Run Failed.
Total tests: 1
     Failed: 1
 Total time: 29.2577 Seconds

📁 Fix files reverted (3 files)
  • src/Controls/src/Core/ContentPage/HideSoftInputOnTappedChanged/HideSoftInputOnTappedChangedManager.Android.cs
  • src/Controls/src/Core/ContentPage/HideSoftInputOnTappedChanged/HideSoftInputOnTappedChangedManager.Platform.cs
  • src/Controls/src/Core/ContentPage/HideSoftInputOnTappedChanged/HideSoftInputOnTappedChangedManager.cs

📱 UI Tests — Focus,Navigation,Page,Shell,SoftInput

Detected UI test categories: Focus,Navigation,Page,Shell,SoftInput

❌ Deep UI tests — 435 passed, 3 failed across 5 categories on platform-pool agent (replaces in-process counts above).

🧪 UI Test Execution Results (deep, platform pool)

Category Tests Snapshot diffs
Focus 2/2 ✓ —
Navigation 88/89 ✓ —
Page 24/26 (2 ❌) —
Shell 308/309 (1 ❌) —
SoftInput 13/13 ✓ —
❌ Page — 2 failed tests
WindowSoftInputModeAdjustSetToResizeForModalPage
Assert.That(beforeEntryRectY, Is.Not.EqualTo(afterEntryRectY))
  Expected: not equal to 863
  But was:  863
at Microsoft.Maui.TestCases.Tests.Issues.Issue27242.WindowSoftInputModeAdjustSetToResizeForModalPage() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue27242.cs:line 29

1)    at Microsoft.Maui.TestCases.Tests.Issues.Issue27242.WindowSoftInputModeAdjustSetToResizeForModalPage() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue27242.cs:line 29
WindowSoftInputModeAdjustSetToPanForModalpage
System.TimeoutException : Timed out waiting for element...
at UITest.Appium.HelperExtensions.Wait(Func`1 query, Func`2 satisfactory, String timeoutMessage, Nullable`1 timeout, Nullable`1 retryFrequency) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 2757
   at UITest.Appium.HelperExtensions.WaitForAtLeastOne(Func`1 query, String timeoutMessage, Nullable`1 timeout, Nullable`1 retryFrequency) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 2784
   at UITest.Appium.HelperExtensions.WaitForElement(IApp app, String marked, String timeoutMessage, Nullable`1 timeout, Nullable`1 retryFrequency, Nullable`1 postTimeout) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 793
   at Microsoft.Maui.TestCases.Tests.Issues.Issue27242.WindowSoftInputModeAdjustSetToPanForModalpage() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue27242.cs:line 37
   at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
   at
...
❌ Shell — 1 failed test
ClearAndRecreateShellElements
System.TimeoutException : Timed out waiting for element...
at UITest.Appium.HelperExtensions.Wait(Func`1 query, Func`2 satisfactory, String timeoutMessage, Nullable`1 timeout, Nullable`1 retryFrequency) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 2757
   at UITest.Appium.HelperExtensions.WaitForAtLeastOne(Func`1 query, String timeoutMessage, Nullable`1 timeout, Nullable`1 retryFrequency) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 2784
   at UITest.Appium.HelperExtensions.WaitForElement(IApp app, String marked, String timeoutMessage, Nullable`1 timeout, Nullable`1 retryFrequency, Nullable`1 postTimeout) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 793
   at Microsoft.Maui.TestCases.Tests.Issues.ShellItemIsVisible.ClearAndRecreateShellElements() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/XFIssue/ShellItemIsVisible.cs:line 66
   at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* arg
...
🔍 AI analysis of failures — PR-related vs unrelated

🔍 AI-generated triage (GitHub Copilot CLI) — a heuristic judgement of whether each deep UI test failure is connected to this PR's changes. Verify before relying on it.

Mixed / uncertain: see the grouped assessment below.

  • ✗ PR-related — Android soft-input modal page behavior (~2 tests): the failures in Issue27242 exercise Android keyboard/window soft-input adjustment on modal pages, and this PR changes Android/shared HideSoftInputOnTappedChangedManager logic that controls when tap/keyboard handling is enabled for the focused page, making the unchanged Y position and missing element plausibly connected.
  • ● Unrelated — Shell element recreation timeout (~1 test): ClearAndRecreateShellElements is a Shell visibility/recreation wait timeout with no stack reference to the changed soft-input manager, and the PR only adds a separate Shell-hosted regression test while changing ContentPage soft-input tap behavior.

Strongest signal: the two Page failures are in the same Android keyboard/input behavior neighborhood as the PR, while the Shell timeout looks like the common “timed out waiting for element” UI-test pattern outside the modified code path.

📎 Download drop-deep-uitests artifact (TRX + snapshot diffs)


📋 Pre-Flight — Context & Validation

Issue: #35890 - HideSoftInputOnTapped="True" on one page permanently affects all other pages if NavigatedFrom is never fired
PR: #36238 - Fixed HideSoftInputOnTapped="True" on one page permanently affects all other pages if NavigatedFrom is never fired
Platforms Affected: Android primary; PR also touches shared Android/iOS code and marks iOS affected
Files Changed: 3 implementation, 2 test

Key Findings

  • The issue is a stale global state bug in HideSoftInputOnTappedChangedManager: a page with HideSoftInputOnTapped=true can remain registered if Shell hides its ShellContent and absolute navigation skips NavigatedFrom.
  • The PR's current fix removes _contentPages and computes from the focused view's enclosing page, but retains a cached FocusedEnclosingPage fallback.
  • Android UI tests were added under Issue35890 with category SoftInput; impacted UI categories: SoftInput, Shell, Navigation, Focus, Page.
  • GitHub CLI was unauthenticated in this environment, so public GitHub API and local branch state were used for context. Required-check status could not be authoritatively queried with gh pr checks.

Code Review Summary

Verdict: NEEDS_CHANGES
Confidence: low
Errors: 1 | Warnings: 1 | Suggestions: 1

Key code review findings:

  • x Cached focused page can reintroduce stale page behavior at HideSoftInputOnTappedChangedManager.Platform.cs:36 and HideSoftInputOnTappedChangedManager.Android.cs:21.
  • ! Test does not focus the login entry before navigating away, so it may not exercise the cached-page stale fallback.
  • i Test comments still reference removed _contentPages implementation details.

Failure-mode probes:

  • Focused input detaches before focus-lost: cached page can remain available and keep the feature enabled.
  • Destination page has HideSoftInputOnTapped=false: Android can still consult the stale cached page before another focus update clears it.
  • No input focused before navigation: the current PR likely fixes the original global-list leak, but not the hardest focused-detach scenario.

Fix Candidates

# Source Approach Test Result Files Changed Notes
PR PR #36238 Remove global page list and resolve the focused view's enclosing page on demand, with a cached enclosing-page fallback PASSED (Gate provided by caller) HideSoftInputOnTappedChangedManager*.cs, Issue35890.cs tests Original PR

🔬 Code Review — Deep Analysis

Code Review -- PR #36238

Independent Assessment

What this changes: Replaces the global _contentPages tracking list for HideSoftInputOnTapped with focused-view lookup: the manager walks FocusedView.Parent to find the enclosing ContentPage, and caches the page when focus is set as a fallback if the view later detaches.

Inferred motivation: Avoid stale page registrations when NavigatedFrom does not fire, so one page's HideSoftInputOnTapped=true does not affect later pages.

Reconciliation with PR Narrative

Author claims: The PR says behavior is now computed from the live visual tree with no stale cache; if the page is gone, FocusedView becomes null and FeatureEnabled returns false.

Agreement/disagreement: The high-level direction is sound, but the implementation still has a cache: GetEnclosingPage(FocusedView) ?? FocusedEnclosingPage. That cached page can preserve the same stale-page class of bug when an input was focused before navigation/hiding.

Prior Review Reconciliation

Prior Error Finding Source Status Evidence
Cached focused page can keep stale dismiss behavior active MauiBot inline/review summary Unresolved Current PR head still has GetEnclosingPage(FocusedView) ?? FocusedEnclosingPage in HideSoftInputOnTappedChangedManager.Platform.cs:36 and Android uses the same fallback at HideSoftInputOnTappedChangedManager.Android.cs:21.
Agent gate failed with fix MauiBot AI summary Unresolved Review body reports Gate Result: FAILED and Issue35890 FAILED with fix; no later commit is present on PR head 91a3d6b.

Blast Radius Assessment

  • Runs for all instances: Yes -- this is shared Android/iOS HideSoftInputOnTapped focus/tap plumbing.
  • Startup impact: No direct startup path.
  • Static/shared state: No static state, but the scoped manager keeps cross-page focused-view state and Android window dispatch subscriptions.

CI Status

  • Required-check result: gh pr checks --required unavailable because gh is unauthenticated.
  • Classification: undetermined from required-check API. Public check-runs for head SHA show maui-pr success; commit status API reports pending/no statuses. Prior MauiBot gate reports PR-specific Issue35890 failure.
  • Action taken: Used public GitHub API/curl fallback; confidence capped low by unresolved prior gate/finding.

Findings

Error -- Cached focused page can reintroduce stale page behavior

HideSoftInputOnTappedChangedManager.Platform.cs:36 falls back from the live parent walk to FocusedEnclosingPage. Android dispatch then uses the same fallback at HideSoftInputOnTappedChangedManager.Android.cs:21.

If a HideSoftInputOnTapped=true page has a focused Entry, then Shell hides/navigates away without NavigatedFrom and before a reliable focus-lost update, the focused view may be detached while _focusedViewEnclosingPage still points to the old page. The next tap can still be evaluated against the cached old page's HideSoftInputOnTapped/HasNavigatedTo, which is the stale-state problem this PR is meant to remove.

Warning -- Test does not cover the cached-page failure path

The new repro logs in via LoginButton without first focusing UsernameEntry (src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue35890.cs:35-37). That means _focusedViewEnclosingPage may never be populated with the outgoing login page before navigation, so the test can pass while the added fallback remains unsafe.

Suggestion -- Update stale test comment

src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue35890.cs:46-47 still says the login page registers in _contentPages, but this PR removes _contentPages.

Failure-Mode Probing

  • Focused input detaches before focus-lost: cached page remains available and can keep feature enabled.
  • Destination page has HideSoftInputOnTapped=false: Android can still consult stale cached page before another input focus clears it.
  • No input focused before navigation: new approach likely fixes the original global-list leak, but this is not the hardest case.
  • Handler/window lifecycle: Android subscription cleanup depends on later focus updates; stale manager state can survive navigation.

Verdict: NEEDS_CHANGES

Confidence: low
Summary: The PR removes the global page list, but the cached focused-page fallback leaves an unresolved stale-state path and prior MauiBot findings/gate failure report the same issue. The tests should cover focusing the login entry before hiding/navigating, and the fallback should be removed or gated on the currently active page/window.


🛠️ Fix — Analysis & Comparison

Fix Candidates

# Source Approach Test Result Files Changed Notes
1 maui-expert-reviewer / try-fix Live focused page only: remove cached enclosing-page fallback and require a live focused-view parent chain PASS 2 files Passed Android Issue35890 runner after script-managed retry; addresses stale-cache review error
PR PR #36238 Remove global _contentPages; compute from focused view parent chain with cached focused-page fallback PASSED (Gate provided) 5 files Original PR; gate was pre-run by caller

Cross-Pollination

Model Round New Ideas? Details
maui-expert-reviewer 1 Yes Proposed live-tree-only candidate, removing the stale cached page fallback.

Exhausted: No
Selected Fix: Candidate #1 -- It passed the Android regression test command and is better than the PR's current fix because it removes the stale cached-page fallback identified by code review while preserving the PR's core live-tree approach.


📝 Recommended PR Title & Description

Assessment: ✏️ Recommend updating — the current title lacks the required platform/component prefix and the description claims there is no cache/stale state, which is inaccurate for the submitted PR and should describe the pr-plus-reviewer winning fix instead.

Recommended title

[Android/iOS] ContentPage: Scope HideSoftInputOnTapped to the live focused page

Recommended description

### Issue Details

`HideSoftInputOnTapped="True"` on one page can permanently affect later pages when Shell hides the outgoing `ShellContent` and navigates with an absolute route without firing `NavigatedFrom`.

### Root Cause

`HideSoftInputOnTappedChangedManager` maintained an internal list of `ContentPage` instances whose `HideSoftInputOnTapped` value was enabled. Pages were added when `NavigatedTo` fired and removed when `NavigatedFrom` fired. In the #35890 scenario, a login `ShellContent` is hidden by setting `IsVisible=false` and then navigating with `GoToAsync("///Route")`; Shell can skip `NavigatedFrom` for the outgoing page, leaving that page registered with `HideSoftInputOnTapped=true`.

Because `FeatureEnabled` was evaluated from the tracked pages, the stale login page could keep tap-to-dismiss enabled globally. Subsequent pages with `HideSoftInputOnTapped=false` could still dismiss the keyboard on tap because the old page remained in the manager state.

### Description of Change

The fix removes the global `_contentPages` tracking list and the `NavigatedFrom` cleanup dependency. Instead, `FeatureEnabled` is computed from the currently focused input view by walking its live `Element.Parent` chain to find the enclosing `ContentPage`.

Android dispatch now resolves the focused view's live enclosing page once and only dispatches the tap-to-dismiss behavior when that page:

- exists in the live parent chain;
- has `HasNavigatedTo=true`;
- has `HideSoftInputOnTapped=true`;
- has a valid platform handler and Maui context;
- contains the tap point.

The winning fix intentionally does not retain a cached enclosing page fallback. If the old focused input is detached from the logical tree before a focus-lost event arrives, it no longer has a live enclosing page and therefore cannot keep the previous page's `HideSoftInputOnTapped=true` behavior active.

**Previous behavior:** `FeatureEnabled` returned `true` if any registered page had `HideSoftInputOnTapped=true`, even if that page was no longer the active or visible page.

**New behavior:** `FeatureEnabled` only reflects the `HideSoftInputOnTapped` value of the page enclosing the currently focused view. Detached focused views do not keep stale page state alive.

### Test Coverage

Added Android/iOS UI coverage for issue #35890:

- Shell `IsVisible=false` + absolute `GoToAsync("///HomePage35890")` navigation where `NavigatedFrom` is skipped.
- A focused outgoing login `Entry` before navigation, to catch stale focused-view/page state.
- A destination page with `HideSoftInputOnTapped=false`, verifying keyboard dismissal does not leak from the login page.
- A classic push-navigation scenario confirming per-page semantics still work when a previous page has `HideSoftInputOnTapped=true` and the current page has it set to `false`.

### What NOT to Do

- Do not reintroduce a global list of pages whose cleanup depends only on `NavigatedFrom`; Shell can skip that event in this scenario.
- Do not use a cached focused enclosing page as a fallback after the focused view detaches; it can preserve the same stale page behavior this fix removes.
- Do not rely on a test that navigates away from the login page without focusing the login input; that misses the stale focused-input path.

### Platforms Tested

- [x] Android
- [ ] Windows
- [x] iOS
- [ ] Mac

### Issues Fixed

Fixes #35890

🏁 Report — Final Recommendation

Comparative Candidate Report

Candidates

Rank Candidate Regression evidence Assessment
1 pr-plus-reviewer Not separately gate-run in this phase; based on the reviewer-applied sandbox candidate and the STEP 5a passing implementation direction. Best candidate. It keeps the PR's intended live focused-view model, removes the stale cached page fallback found by expert review, and adds coverage for the focused outgoing login entry path.
2 try-fix-1 PASS. Android Issue35890 filtered UI run passed under the repository retry policy. Strong alternative. It removes the cached FocusedEnclosingPage fallback and only enables the feature when the focused view still resolves to a live enclosing page. It does not include the additional focused-login test/comment cleanup applied in pr-plus-reviewer.
3 pr Gate was provided as passed by the caller, but expert review found an unresolved stale-cache path in the current diff. Prior local review artifacts also recorded a failing gate result for the same stale-cache concern. Directionally correct because it removes _contentPages, but not acceptable as submitted: GetEnclosingPage(FocusedView) ?? FocusedEnclosingPage can preserve old page state after detach.

Candidate details

pr

The raw PR removes the global page list and computes behavior from the currently focused input view's page. However, it keeps _focusedViewEnclosingPage as a weak cached fallback. That fallback contradicts the PR description's claim that there is no cache/stale state and can preserve the old login page when Shell hides/navigates away without NavigatedFrom.

try-fix-1

try-fix-1 removes the cached fallback and uses only the live focused-view parent chain. It passed the Android Issue35890 runner after script-managed retry:

pwsh .github/scripts/BuildAndRunHostApp.ps1 -Platform android -TestFilter "FullyQualifiedName~Issue35890"

This candidate directly addresses the expert review error while changing only the focused-page source of truth.

pr-plus-reviewer

pr-plus-reviewer applies the expert review feedback to the PR approach: no cached focused page fallback, Android dispatch uses only the live focused page, and the regression test focuses UsernameEntry before navigating away so it covers stale focused-input/page state. It is the strict improvement over both the raw PR and try-fix-1 because it combines the passing core approach with the reviewer's requested coverage fix.

Winning candidate

pr-plus-reviewer wins. It keeps the PR's simplest correct model and removes the stale state path identified by expert review, while adding the missing focused-input regression coverage. Candidates with known or unresolved regression failures are ranked below candidates that passed or directly incorporate the passing STEP 5a fix direction.


🧭 Next Steps — review latest findings

No alternative fix was selected for this run. Review the session findings and CI results before merging.

@MauiBot MauiBot removed the s/agent-review-in-progress AI review is currently running for this PR label Jul 15, 2026

@kubaflo kubaflo left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like some failing tests are related - could you please verify?

@kubaflo

This comment has been minimized.

@github-actions

Copy link
Copy Markdown
Contributor

Tests Failure Analysis

@KarthikRajaKalaimani — test-failure review results are available based on commit 91a3d6b.
To request a fresh review after new comments, commits, or CI runs, comment /review tests.

Overall No failures found Failures 0 Regressed vs base 0 Baseline 0 on base

Test Failure Review: No failures found - click to expand

Overall verdict: No failures found — all 31 GitHub status checks completed as passing, neutral, or skipped, with no failing, pending, or inconclusive checks in the rollup. The maui-pr build (buildId 1491599) succeeded across every leg, and no distinct test failures were extracted. No base-branch (main) builds were needed since there were no PR failures to attribute.

Coverage: 31 checks · 31 passing · 0 failing · 0 pending · 0 inaccessible · 0 unmapped · 0 unexplained build legs · 0 unaccounted failing checks · 0 aborted failing checks · 0 canceled-build checks · 0 device-test unverified · 0 unattributed · 0 regressed-vs-base. Deterministic ceiling: No failures found.

Builds (this PR): maui-pr buildId 1491599. Base sampling (main, 0 recent builds): none required — no PR failures to compare.

Recommended action

No test-failure action is needed; CI is clean for this commit.

@kubaflo
kubaflo changed the base branch from main to inflight/current July 18, 2026 15:38
@kubaflo
kubaflo marked this pull request as ready for review July 18, 2026 15:39
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).
There may be pipelines that require an authorized user to comment /azp run to run.

@kubaflo
kubaflo merged commit 5dfcab5 into dotnet:inflight/current Jul 18, 2026
36 of 37 checks passed
@github-actions github-actions Bot added this to the .NET 10 SR10 milestone Jul 18, 2026
kubaflo pushed a commit that referenced this pull request Jul 22, 2026
…l other pages if NavigatedFrom is never fired (#36238)

<!-- 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:

HideSoftInputOnTapped="True" on one page permanently affects all other
pages
       
### Root Cause:

HideSoftInputOnTappedChangedManager maintained an internal
List<ContentPage> _contentPages to track which pages had
HideSoftInputOnTapped="True" enabled. Pages were added to this list when
NavigatedTo fired on them, and removed when NavigatedFrom fired. The
FeatureEnabled property iterated this list to decide whether the global
tap-to-dismiss keyboard behavior should be active. The critical flaw was
that this entire cleanup mechanism depended solely on NavigatedFrom
firing. In the specific scenario described in issue #35890 — where a
ShellContent is hidden by setting IsVisible=false followed by an
absolute GoToAsync("///Route") call — the Shell framework skips firing
NavigatedFrom on the outgoing page entirely. As a result, the login page
remained permanently registered in _contentPages with
HideSoftInputOnTapped=true, keeping FeatureEnabled=true globally. Every
subsequent page in the app — even pages with HideSoftInputOnTapped=false
— had the keyboard dismissed on tap, because the stale login page entry
in the list kept overriding the correct behavior.

### Description of Change:

The fix eliminates _contentPages and the event-subscription model
entirely. Instead of maintaining a tracked list of pages, FeatureEnabled
is now computed on-demand by walking the Element.Parent chain upward
from the currently focused input view (FocusedView). A new static helper
GetEnclosingPage(IView?) traverses the parent chain until it finds the
enclosing ContentPage, then reads HideSoftInputOnTapped and
HasNavigatedTo directly from that live page instance. Since the result
is computed from the actual visual tree at the moment of the query,
there is no cache and no stale state possible — if the page is gone from
the tree, FocusedView becomes null and FeatureEnabled returns false
automatically. This also resolves a secondary regression that existed in
an earlier Unloaded-based fix: if a page was re-shown after being
hidden, the old approach would permanently break for that page instance
because HasNavigatedTo was never reset. With the parent-chain walk, the
live property values are always used, so re-show scenarios work
correctly without any special handling. The UpdatePage method, which
previously managed list mutations and event subscriptions, is now a
single line that re-evaluates the tap watcher setup. The
Android-specific OnWindowDispatchedTouch handler is similarly simplified
— instead of looping over the list, it calls
GetEnclosingPage(FocusedView) once and acts on the result directly.

**Previous behavior:** `FeatureEnabled` returned `true` if *any*
registered page had
`HideSoftInputOnTapped` set to `true` — even if that page was no longer
the active/visible
page (this was the root cause of #35890, the "sticky" keyboard-dismissal
bug). In effect, one
page's setting could leak and affect the keyboard behavior on unrelated
pages.

**New behavior:** `FeatureEnabled` now only checks the page enclosing
the currently focused
view. Only the active page's `HideSoftInputOnTapped` value applies.
**Tested the behavior in the following platforms: **

- [x] Android
- [ ] Windows
- [x] iOS
- [ ] Mac

### Reference:

N/A

### Issues Fixed:

Fixes  #35890           

### Screenshots
| Before  | After  |
|---------|--------|
| <Video
src="https://github.com/user-attachments/assets/7365d6d3-2cef-40ee-94b9-9ce2acc1b718"
Width="600" Height="300"/> | <Video
src="https://github.com/user-attachments/assets/10e59ac3-a381-4053-95c8-061eb8b3eaa4"
Width="600" Height="300"/> |

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
kubaflo pushed a commit that referenced this pull request Jul 28, 2026
…l other pages if NavigatedFrom is never fired (#36238)

<!-- 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:

HideSoftInputOnTapped="True" on one page permanently affects all other
pages
       
### Root Cause:

HideSoftInputOnTappedChangedManager maintained an internal
List<ContentPage> _contentPages to track which pages had
HideSoftInputOnTapped="True" enabled. Pages were added to this list when
NavigatedTo fired on them, and removed when NavigatedFrom fired. The
FeatureEnabled property iterated this list to decide whether the global
tap-to-dismiss keyboard behavior should be active. The critical flaw was
that this entire cleanup mechanism depended solely on NavigatedFrom
firing. In the specific scenario described in issue #35890 — where a
ShellContent is hidden by setting IsVisible=false followed by an
absolute GoToAsync("///Route") call — the Shell framework skips firing
NavigatedFrom on the outgoing page entirely. As a result, the login page
remained permanently registered in _contentPages with
HideSoftInputOnTapped=true, keeping FeatureEnabled=true globally. Every
subsequent page in the app — even pages with HideSoftInputOnTapped=false
— had the keyboard dismissed on tap, because the stale login page entry
in the list kept overriding the correct behavior.

### Description of Change:

The fix eliminates _contentPages and the event-subscription model
entirely. Instead of maintaining a tracked list of pages, FeatureEnabled
is now computed on-demand by walking the Element.Parent chain upward
from the currently focused input view (FocusedView). A new static helper
GetEnclosingPage(IView?) traverses the parent chain until it finds the
enclosing ContentPage, then reads HideSoftInputOnTapped and
HasNavigatedTo directly from that live page instance. Since the result
is computed from the actual visual tree at the moment of the query,
there is no cache and no stale state possible — if the page is gone from
the tree, FocusedView becomes null and FeatureEnabled returns false
automatically. This also resolves a secondary regression that existed in
an earlier Unloaded-based fix: if a page was re-shown after being
hidden, the old approach would permanently break for that page instance
because HasNavigatedTo was never reset. With the parent-chain walk, the
live property values are always used, so re-show scenarios work
correctly without any special handling. The UpdatePage method, which
previously managed list mutations and event subscriptions, is now a
single line that re-evaluates the tap watcher setup. The
Android-specific OnWindowDispatchedTouch handler is similarly simplified
— instead of looping over the list, it calls
GetEnclosingPage(FocusedView) once and acts on the result directly.

**Previous behavior:** `FeatureEnabled` returned `true` if *any*
registered page had
`HideSoftInputOnTapped` set to `true` — even if that page was no longer
the active/visible
page (this was the root cause of #35890, the "sticky" keyboard-dismissal
bug). In effect, one
page's setting could leak and affect the keyboard behavior on unrelated
pages.

**New behavior:** `FeatureEnabled` now only checks the page enclosing
the currently focused
view. Only the active page's `HideSoftInputOnTapped` value applies.
**Tested the behavior in the following platforms: **

- [x] Android
- [ ] Windows
- [x] iOS
- [ ] Mac

### Reference:

N/A

### Issues Fixed:

Fixes  #35890           

### Screenshots
| Before  | After  |
|---------|--------|
| <Video
src="https://github.com/user-attachments/assets/7365d6d3-2cef-40ee-94b9-9ce2acc1b718"
Width="600" Height="300"/> | <Video
src="https://github.com/user-attachments/assets/10e59ac3-a381-4053-95c8-061eb8b3eaa4"
Width="600" Height="300"/> |

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
kubaflo pushed a commit that referenced this pull request Jul 29, 2026
…l other pages if NavigatedFrom is never fired (#36238)

<!-- 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:

HideSoftInputOnTapped="True" on one page permanently affects all other
pages
       
### Root Cause:

HideSoftInputOnTappedChangedManager maintained an internal
List<ContentPage> _contentPages to track which pages had
HideSoftInputOnTapped="True" enabled. Pages were added to this list when
NavigatedTo fired on them, and removed when NavigatedFrom fired. The
FeatureEnabled property iterated this list to decide whether the global
tap-to-dismiss keyboard behavior should be active. The critical flaw was
that this entire cleanup mechanism depended solely on NavigatedFrom
firing. In the specific scenario described in issue #35890 — where a
ShellContent is hidden by setting IsVisible=false followed by an
absolute GoToAsync("///Route") call — the Shell framework skips firing
NavigatedFrom on the outgoing page entirely. As a result, the login page
remained permanently registered in _contentPages with
HideSoftInputOnTapped=true, keeping FeatureEnabled=true globally. Every
subsequent page in the app — even pages with HideSoftInputOnTapped=false
— had the keyboard dismissed on tap, because the stale login page entry
in the list kept overriding the correct behavior.

### Description of Change:

The fix eliminates _contentPages and the event-subscription model
entirely. Instead of maintaining a tracked list of pages, FeatureEnabled
is now computed on-demand by walking the Element.Parent chain upward
from the currently focused input view (FocusedView). A new static helper
GetEnclosingPage(IView?) traverses the parent chain until it finds the
enclosing ContentPage, then reads HideSoftInputOnTapped and
HasNavigatedTo directly from that live page instance. Since the result
is computed from the actual visual tree at the moment of the query,
there is no cache and no stale state possible — if the page is gone from
the tree, FocusedView becomes null and FeatureEnabled returns false
automatically. This also resolves a secondary regression that existed in
an earlier Unloaded-based fix: if a page was re-shown after being
hidden, the old approach would permanently break for that page instance
because HasNavigatedTo was never reset. With the parent-chain walk, the
live property values are always used, so re-show scenarios work
correctly without any special handling. The UpdatePage method, which
previously managed list mutations and event subscriptions, is now a
single line that re-evaluates the tap watcher setup. The
Android-specific OnWindowDispatchedTouch handler is similarly simplified
— instead of looping over the list, it calls
GetEnclosingPage(FocusedView) once and acts on the result directly.

**Previous behavior:** `FeatureEnabled` returned `true` if *any*
registered page had
`HideSoftInputOnTapped` set to `true` — even if that page was no longer
the active/visible
page (this was the root cause of #35890, the "sticky" keyboard-dismissal
bug). In effect, one
page's setting could leak and affect the keyboard behavior on unrelated
pages.

**New behavior:** `FeatureEnabled` now only checks the page enclosing
the currently focused
view. Only the active page's `HideSoftInputOnTapped` value applies.
**Tested the behavior in the following platforms: **

- [x] Android
- [ ] Windows
- [x] iOS
- [ ] Mac

### Reference:

N/A

### Issues Fixed:

Fixes  #35890           

### Screenshots
| Before  | After  |
|---------|--------|
| <Video
src="https://github.com/user-attachments/assets/7365d6d3-2cef-40ee-94b9-9ce2acc1b718"
Width="600" Height="300"/> | <Video
src="https://github.com/user-attachments/assets/10e59ac3-a381-4053-95c8-061eb8b3eaa4"
Width="600" Height="300"/> |

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
kubaflo pushed a commit that referenced this pull request Aug 7, 2026
…l other pages if NavigatedFrom is never fired (#36238)

<!-- 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:

HideSoftInputOnTapped="True" on one page permanently affects all other
pages
       
### Root Cause:

HideSoftInputOnTappedChangedManager maintained an internal
List<ContentPage> _contentPages to track which pages had
HideSoftInputOnTapped="True" enabled. Pages were added to this list when
NavigatedTo fired on them, and removed when NavigatedFrom fired. The
FeatureEnabled property iterated this list to decide whether the global
tap-to-dismiss keyboard behavior should be active. The critical flaw was
that this entire cleanup mechanism depended solely on NavigatedFrom
firing. In the specific scenario described in issue #35890 — where a
ShellContent is hidden by setting IsVisible=false followed by an
absolute GoToAsync("///Route") call — the Shell framework skips firing
NavigatedFrom on the outgoing page entirely. As a result, the login page
remained permanently registered in _contentPages with
HideSoftInputOnTapped=true, keeping FeatureEnabled=true globally. Every
subsequent page in the app — even pages with HideSoftInputOnTapped=false
— had the keyboard dismissed on tap, because the stale login page entry
in the list kept overriding the correct behavior.

### Description of Change:

The fix eliminates _contentPages and the event-subscription model
entirely. Instead of maintaining a tracked list of pages, FeatureEnabled
is now computed on-demand by walking the Element.Parent chain upward
from the currently focused input view (FocusedView). A new static helper
GetEnclosingPage(IView?) traverses the parent chain until it finds the
enclosing ContentPage, then reads HideSoftInputOnTapped and
HasNavigatedTo directly from that live page instance. Since the result
is computed from the actual visual tree at the moment of the query,
there is no cache and no stale state possible — if the page is gone from
the tree, FocusedView becomes null and FeatureEnabled returns false
automatically. This also resolves a secondary regression that existed in
an earlier Unloaded-based fix: if a page was re-shown after being
hidden, the old approach would permanently break for that page instance
because HasNavigatedTo was never reset. With the parent-chain walk, the
live property values are always used, so re-show scenarios work
correctly without any special handling. The UpdatePage method, which
previously managed list mutations and event subscriptions, is now a
single line that re-evaluates the tap watcher setup. The
Android-specific OnWindowDispatchedTouch handler is similarly simplified
— instead of looping over the list, it calls
GetEnclosingPage(FocusedView) once and acts on the result directly.

**Previous behavior:** `FeatureEnabled` returned `true` if *any*
registered page had
`HideSoftInputOnTapped` set to `true` — even if that page was no longer
the active/visible
page (this was the root cause of #35890, the "sticky" keyboard-dismissal
bug). In effect, one
page's setting could leak and affect the keyboard behavior on unrelated
pages.

**New behavior:** `FeatureEnabled` now only checks the page enclosing
the currently focused
view. Only the active page's `HideSoftInputOnTapped` value applies.
**Tested the behavior in the following platforms: **

- [x] Android
- [ ] Windows
- [x] iOS
- [ ] Mac

### Reference:

N/A

### Issues Fixed:

Fixes  #35890           

### Screenshots
| Before  | After  |
|---------|--------|
| <Video
src="https://github.com/user-attachments/assets/7365d6d3-2cef-40ee-94b9-9ce2acc1b718"
Width="600" Height="300"/> | <Video
src="https://github.com/user-attachments/assets/10e59ac3-a381-4053-95c8-061eb8b3eaa4"
Width="600" Height="300"/> |

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
kubaflo pushed a commit that referenced this pull request Aug 12, 2026
…l other pages if NavigatedFrom is never fired (#36238)

<!-- 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:

HideSoftInputOnTapped="True" on one page permanently affects all other
pages
       
### Root Cause:

HideSoftInputOnTappedChangedManager maintained an internal
List<ContentPage> _contentPages to track which pages had
HideSoftInputOnTapped="True" enabled. Pages were added to this list when
NavigatedTo fired on them, and removed when NavigatedFrom fired. The
FeatureEnabled property iterated this list to decide whether the global
tap-to-dismiss keyboard behavior should be active. The critical flaw was
that this entire cleanup mechanism depended solely on NavigatedFrom
firing. In the specific scenario described in issue #35890 — where a
ShellContent is hidden by setting IsVisible=false followed by an
absolute GoToAsync("///Route") call — the Shell framework skips firing
NavigatedFrom on the outgoing page entirely. As a result, the login page
remained permanently registered in _contentPages with
HideSoftInputOnTapped=true, keeping FeatureEnabled=true globally. Every
subsequent page in the app — even pages with HideSoftInputOnTapped=false
— had the keyboard dismissed on tap, because the stale login page entry
in the list kept overriding the correct behavior.

### Description of Change:

The fix eliminates _contentPages and the event-subscription model
entirely. Instead of maintaining a tracked list of pages, FeatureEnabled
is now computed on-demand by walking the Element.Parent chain upward
from the currently focused input view (FocusedView). A new static helper
GetEnclosingPage(IView?) traverses the parent chain until it finds the
enclosing ContentPage, then reads HideSoftInputOnTapped and
HasNavigatedTo directly from that live page instance. Since the result
is computed from the actual visual tree at the moment of the query,
there is no cache and no stale state possible — if the page is gone from
the tree, FocusedView becomes null and FeatureEnabled returns false
automatically. This also resolves a secondary regression that existed in
an earlier Unloaded-based fix: if a page was re-shown after being
hidden, the old approach would permanently break for that page instance
because HasNavigatedTo was never reset. With the parent-chain walk, the
live property values are always used, so re-show scenarios work
correctly without any special handling. The UpdatePage method, which
previously managed list mutations and event subscriptions, is now a
single line that re-evaluates the tap watcher setup. The
Android-specific OnWindowDispatchedTouch handler is similarly simplified
— instead of looping over the list, it calls
GetEnclosingPage(FocusedView) once and acts on the result directly.

**Previous behavior:** `FeatureEnabled` returned `true` if *any*
registered page had
`HideSoftInputOnTapped` set to `true` — even if that page was no longer
the active/visible
page (this was the root cause of #35890, the "sticky" keyboard-dismissal
bug). In effect, one
page's setting could leak and affect the keyboard behavior on unrelated
pages.

**New behavior:** `FeatureEnabled` now only checks the page enclosing
the currently focused
view. Only the active page's `HideSoftInputOnTapped` value applies.
**Tested the behavior in the following platforms: **

- [x] Android
- [ ] Windows
- [x] iOS
- [ ] Mac

### Reference:

N/A

### Issues Fixed:

Fixes  #35890           

### Screenshots
| Before  | After  |
|---------|--------|
| <Video
src="https://github.com/user-attachments/assets/7365d6d3-2cef-40ee-94b9-9ce2acc1b718"
Width="600" Height="300"/> | <Video
src="https://github.com/user-attachments/assets/10e59ac3-a381-4053-95c8-061eb8b3eaa4"
Width="600" Height="300"/> |

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions github-actions Bot locked and limited conversation to collaborators Aug 18, 2026
@sheiksyedm sheiksyedm modified the milestones: .NET 10 SR10, .NET 10 SR11 Aug 26, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

community ✨ Community Contribution partner/syncfusion Issues / PR's with Syncfusion collaboration s/agent-fix-pr-picked AI could not beat the PR fix - PR is the best among all candidates s/agent-gate-passed AI verified tests catch the bug (fail without fix, pass with fix) s/agent-reviewed PR was reviewed by AI agent workflow (full 4-phase review)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

HideSoftInputOnTapped="True" on one page permanently affects all other pages if NavigatedFrom is never fired

5 participants