Skip to content

[Android] Fix for CurrentItem is updated incorrectly when the CarouselView is bound to an ObservableCollection with Loop = false - #36243

Merged
kubaflo merged 11 commits into
dotnet:inflight/currentfrom
BagavathiPerumal:fix-35643
Jul 17, 2026
Merged

[Android] Fix for CurrentItem is updated incorrectly when the CarouselView is bound to an ObservableCollection with Loop = false#36243
kubaflo merged 11 commits into
dotnet:inflight/currentfrom
BagavathiPerumal:fix-35643

Conversation

@BagavathiPerumal

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

The issue occurs on Android when replacing an item in the CarouselView.ItemsSource while Loop is set to false and simultaneously updating the CurrentItem. If the replaced item is the currently selected item, CarouselView incorrectly resets the selection to the first item instead of preserving the updated item as the current selection.

Root Cause

When ItemsUpdatingScrollMode support was added to CarouselView collection change handling on Android, the change correctly implemented scroll-mode logic for Add, Remove, and Reset actions but did not add a dedicated path for the Replace action. This caused Replace to fall through into the KeepItemsInView/KeepLastItemInView scroll logic.

GetPosition(CurrentItem) always returns -1 after a Replace (old item gone from source), making removingCurrentElement = true and triggering a position reset to 0.

Description of Change

The fix involves intercepting the Replace action at the top of CollectionItemsSourceChanged — before any Remove/Insert flags are computed — and delegating to a dedicated HandleReplaceAction method, ensuring Replace never reaches the KeepItemsInView reset logic.

For non-loop mode, SetCurrentItem and UpdatePosition are dispatched at the preserved position with no scroll. For loop mode, a new RebindVisibleLoopItem helper surgically rebinds only the visible virtual cells that map to the replaced real index, avoiding a full adapter rebuild that previously caused a flash to position 0 and spurious events. All existing Remove, Reset, and Insert behavior is fully preserved.

Regression PR

PR #26608

Tested the behavior in the following platforms.

  • Android
  • Mac
  • iOS
  • Windows

Issues Fixed

Fixes #35643

Output

Platform Before After
Android
35643-BeforeFix-Android.mov
35643-AfterFix-Android.mov

@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 -- 36243

Or

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

@dotnet-policy-service dotnet-policy-service Bot added the partner/syncfusion Issues / PR's with Syncfusion collaboration label Jun 30, 2026
@github-actions github-actions Bot added area-controls-collectionview CollectionView, CarouselView, IndicatorView platform/android labels Jun 30, 2026
@Tamilarasan-Paranthaman Tamilarasan-Paranthaman added the community ✨ Community Contribution label Jun 30, 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 Jun 30, 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.

Comment thread src/Controls/src/Core/Handlers/Items/Android/MauiCarouselRecyclerView.cs Outdated
@MauiBot MauiBot added s/agent-gate-passed AI verified tests catch the bug (fail without fix, pass with fix) 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 Jun 30, 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 Jun 30, 2026
@BagavathiPerumal

Copy link
Copy Markdown
Contributor Author

AI Review Summary

@BagavathiPerumal — new AI review results are available based on this last commit: c7ecdb8. 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: 6e107357

Test Without Fix (expect FAIL) With Fix (expect PASS)
🖥️ Issue35643 Issue35643 ✅ FAIL — 1342s ✅ PASS — 706s
🔴 Without fix — 🖥️ Issue35643: FAIL ✅ · 1342s
(truncated to last 15,000 chars)

 /home/vsts/work/1/s/src/Core/maps/src/Maps.csproj (in 747 ms).
  Restored /home/vsts/work/1/s/src/Controls/src/Core/Controls.Core.csproj (in 26 ms).
  Restored /home/vsts/work/1/s/src/Controls/Maps/src/Controls.Maps.csproj (in 36 ms).
  Restored /home/vsts/work/1/s/src/Controls/Foldable/src/Controls.Foldable.csproj (in 353 ms).
  Restored /home/vsts/work/1/s/src/BlazorWebView/src/Maui/Microsoft.AspNetCore.Components.WebView.Maui.csproj (in 113 ms).
  Restored /home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj (in 1.57 sec).
  1 of 11 projects are up-to-date for restore.
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529355
  Graphics -> /home/vsts/work/1/s/artifacts/bin/Graphics/Debug/net10.0-android36.0/Microsoft.Maui.Graphics.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529355
  Essentials -> /home/vsts/work/1/s/artifacts/bin/Essentials/Debug/net10.0-android36.0/Microsoft.Maui.Essentials.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529355
  Core -> /home/vsts/work/1/s/artifacts/bin/Core/Debug/net10.0-android36.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.90-ci+azdo.14529355
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529355
  Maps -> /home/vsts/work/1/s/artifacts/bin/Maps/Debug/net10.0-android36.0/Microsoft.Maui.Maps.dll
  Controls.Core -> /home/vsts/work/1/s/artifacts/bin/Controls.Core/Debug/net10.0-android36.0/Microsoft.Maui.Controls.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529355
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529355
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529355
  Controls.Maps -> /home/vsts/work/1/s/artifacts/bin/Controls.Maps/Debug/net10.0-android36.0/Microsoft.Maui.Controls.Maps.dll
  Controls.Xaml -> /home/vsts/work/1/s/artifacts/bin/Controls.Xaml/Debug/net10.0-android36.0/Microsoft.Maui.Controls.Xaml.dll
  Controls.Foldable -> /home/vsts/work/1/s/artifacts/bin/Controls.Foldable/Debug/net10.0-android36.0/Microsoft.Maui.Controls.Foldable.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529355
  Microsoft.AspNetCore.Components.WebView.Maui -> /home/vsts/work/1/s/artifacts/bin/Microsoft.AspNetCore.Components.WebView.Maui/Debug/net10.0-android36.0/Microsoft.AspNetCore.Components.WebView.Maui.dll
  Controls.TestCases.HostApp -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Controls.TestCases.HostApp.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529355
  Graphics -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Graphics.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529355
  Essentials -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Essentials.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529355
  Core -> /home/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.90-ci+azdo.14529355
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529355
  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.90-ci+azdo.14529355
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529355
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529355
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529355
  Controls.Foldable -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Controls.Foldable.dll
  Controls.Maps -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Controls.Maps.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

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

Time Elapsed 00:09:53.80
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/TestUtils/src/VisualTestUtils/VisualTestUtils.csproj (in 1.21 sec).
  Retrying 'FindPackagesByIdAsync' for source 'https://pkgs.dev.azure.com/dnceng/9ee6d478-d288-47f7-aacc-f6e6d082ae6d/_packaging/f1040238-e8b2-49c9-84cf-abd79c186da2/nuget/v3/flat2/netstandard.library/index.json'.
  An error occurred while sending the request.
    Unable to read data from the transport connection: Connection reset by peer.
    Connection reset by peer
  Failed to download package 'NETStandard.Library.2.0.0' from 'https://pkgs.dev.azure.com/dnceng/9ee6d478-d288-47f7-aacc-f6e6d082ae6d/_packaging/45bacae2-5efb-47c8-91e5-8ec20c22b4f8/nuget/v3/flat2/netstandard.library/2.0.0/netstandard.library.2.0.0.nupkg'.
  An error occurred while sending the request.
    Unable to read data from the transport connection: Connection reset by peer.
    Connection reset by peer
  Retrying 'FindPackagesByIdAsync' for source 'https://pkgs.dev.azure.com/dnceng/9ee6d478-d288-47f7-aacc-f6e6d082ae6d/_packaging/45bacae2-5efb-47c8-91e5-8ec20c22b4f8/nuget/v3/flat2/magick.net.core/index.json'.
  An error occurred while sending the request.
    Unable to read data from the transport connection: Connection reset by peer.
    Connection reset by peer
  Restored /home/vsts/work/1/s/src/TestUtils/src/UITest.NUnit/UITest.NUnit.csproj (in 3.25 sec).
  Restored /home/vsts/work/1/s/src/TestUtils/src/UITest.Core/UITest.Core.csproj (in 4 ms).
  Retrying 'FindPackagesByIdAsync' for source 'https://pkgs.dev.azure.com/dnceng/9ee6d478-d288-47f7-aacc-f6e6d082ae6d/_packaging/d1622942-d16f-48e5-bc83-96f4539e7601/nuget/v3/flat2/xunit.runner.console/index.json'.
  An error occurred while sending the request.
    Unable to read data from the transport connection: Connection reset by peer.
    Connection reset by peer
  Restored /home/vsts/work/1/s/src/TestUtils/src/VisualTestUtils.MagickNet/VisualTestUtils.MagickNet.csproj (in 8.97 sec).
  Restored /home/vsts/work/1/s/src/Controls/tests/CustomAttributes/Controls.CustomAttributes.csproj (in 8 ms).
  Restored /home/vsts/work/1/s/src/TestUtils/src/UITest.Appium/UITest.Appium.csproj (in 12 ms).
  Restored /home/vsts/work/1/s/src/Controls/tests/TestCases.Android.Tests/Controls.TestCases.Android.Tests.csproj (in 4.46 sec).
  Restored /home/vsts/work/1/s/src/TestUtils/src/UITest.Analyzers/UITest.Analyzers.csproj (in 2.54 sec).
  5 of 13 projects are up-to-date for restore.
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529355
  Controls.CustomAttributes -> /home/vsts/work/1/s/artifacts/bin/Controls.CustomAttributes/Debug/net10.0/Controls.CustomAttributes.dll
  Graphics -> /home/vsts/work/1/s/artifacts/bin/Graphics/Debug/net10.0/Microsoft.Maui.Graphics.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529355
  Essentials -> /home/vsts/work/1/s/artifacts/bin/Essentials/Debug/net10.0/Microsoft.Maui.Essentials.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529355
  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.90-ci+azdo.14529355
  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 1 of 1 NUnit test cases using Current Discovery mode, Non-Explicit run
>>>>> 06/30/2026 14:49:07 FixtureSetup for Issue35643(Android)
>>>>> 06/30/2026 14:53:04 The FixtureSetup threw an exception. Attempt 0/1.
Exception details: System.TimeoutException: CurrentItem is updated incorrectly on Android when the CarouselView is bound to an ObservableCollection with Loop = false (the app did not recover after crash-recovery attempts)
   at Microsoft.Maui.TestCases.Tests.UtilExtensions.WaitForGoToTestButtonWithRecovery(IApp app, String timeoutMessage) in /_/src/Controls/tests/TestCases.Shared.Tests/UtilExtensions.cs:line 91
   at Microsoft.Maui.TestCases.Tests._IssuesUITest.NavigateToIssue(String issue) in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/_IssuesUITest.cs:line 54
   at Microsoft.Maui.TestCases.Tests._IssuesUITest.TryToResetTestState() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/_IssuesUITest.cs:line 25
   at Microsoft.Maui.TestCases.Tests.UITest.FixtureSetup() in /_/src/Controls/tests/TestCases.Shared.Tests/UITest.cs:line 576
>>>>> 06/30/2026 14:53:06 FixtureSetup for Issue35643(Android)
>>>>> 06/30/2026 14:56:58 The FixtureSetup threw an exception. Attempt 1/1.
Exception details: System.TimeoutException: CurrentItem is updated incorrectly on Android when the CarouselView is bound to an ObservableCollection with Loop = false (the app did not recover after crash-recovery attempts)
   at Microsoft.Maui.TestCases.Tests.UtilExtensions.WaitForGoToTestButtonWithRecovery(IApp app, String timeoutMessage) in /_/src/Controls/tests/TestCases.Shared.Tests/UtilExtensions.cs:line 91
   at Microsoft.Maui.TestCases.Tests._IssuesUITest.NavigateToIssue(String issue) in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/_IssuesUITest.cs:line 54
   at Microsoft.Maui.TestCases.Tests._IssuesUITest.TryToResetTestState() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/_IssuesUITest.cs:line 25
   at Microsoft.Maui.TestCases.Tests.UITest.FixtureSetup() in /_/src/Controls/tests/TestCases.Shared.Tests/UITest.cs:line 576
>>>>> 06/30/2026 14:56:58 Log types: logcat, bugreport, server
>>>>> 06/30/2026 14:56:59 Log types: logcat, bugreport, server
  Failed CurrentItemShouldUpdateWhenCurrentItemIsReplaced [8 m 53 s]
  Error Message:
   OneTimeSetUp: System.TimeoutException : CurrentItem is updated incorrectly on Android when the CarouselView is bound to an ObservableCollection with Loop = false (the app did not recover after crash-recovery attempts)
  Stack Trace:
     at Microsoft.Maui.TestCases.Tests.UtilExtensions.WaitForGoToTestButtonWithRecovery(IApp app, String timeoutMessage) in /_/src/Controls/tests/TestCases.Shared.Tests/UtilExtensions.cs:line 91
   at Microsoft.Maui.TestCases.Tests._IssuesUITest.NavigateToIssue(String issue) in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/_IssuesUITest.cs:line 54
   at Microsoft.Maui.TestCases.Tests._IssuesUITest.TryToResetTestState() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/_IssuesUITest.cs:line 25
   at Microsoft.Maui.TestCases.Tests.UITest.FixtureSetup() in /_/src/Controls/tests/TestCases.Shared.Tests/UITest.cs:line 576
   at UITest.Appium.NUnit.UITestBase.OneTimeSetup() in /_/src/TestUtils/src/UITest.NUnit/UITestBase.cs:line 221
   at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
   at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)

Setup failed for test fixture Microsoft.Maui.TestCases.Tests.Issues.Issue35643(Android)
System.TimeoutException : CurrentItem is updated incorrectly on Android when the CarouselView is bound to an ObservableCollection with Loop = false (the app did not recover after crash-recovery attempts)
StackTrace:    at Microsoft.Maui.TestCases.Tests.UtilExtensions.WaitForGoToTestButtonWithRecovery(IApp app, String timeoutMessage) in /_/src/Controls/tests/TestCases.Shared.Tests/UtilExtensions.cs:line 91
   at Microsoft.Maui.TestCases.Tests._IssuesUITest.NavigateToIssue(String issue) in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/_IssuesUITest.cs:line 54
   at Microsoft.Maui.TestCases.Tests._IssuesUITest.TryToResetTestState() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/_IssuesUITest.cs:line 25
   at Microsoft.Maui.TestCases.Tests.UITest.FixtureSetup() in /_/src/Controls/tests/TestCases.Shared.Tests/UITest.cs:line 576
   at UITest.Appium.NUnit.UITestBase.OneTimeSetup() in /_/src/TestUtils/src/UITest.NUnit/UITestBase.cs:line 221
   at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
   at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)
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.21]   Discovering: Controls.TestCases.Android.Tests
[xUnit.net 00:00:01.06]   Discovered:  Controls.TestCases.Android.Tests
Results File: /home/vsts/work/1/s/CustomAgentLogsTmp/UITests/TestResults/Issue35643.trx

Total tests: 1
     Failed: 1
Test Run Failed.
 Total time: 9.0981 Minutes
>>> TRX_RESULT_FILE: /home/vsts/work/1/s/CustomAgentLogsTmp/UITests/TestResults/Issue35643.trx

🟢 With fix — 🖥️ Issue35643: PASS ✅ · 706s

  Determining projects to restore...
  All projects are up-to-date for restore.
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529355
  Graphics -> /home/vsts/work/1/s/artifacts/bin/Graphics/Debug/net10.0-android36.0/Microsoft.Maui.Graphics.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529355
  Essentials -> /home/vsts/work/1/s/artifacts/bin/Essentials/Debug/net10.0-android36.0/Microsoft.Maui.Essentials.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529355
  Core -> /home/vsts/work/1/s/artifacts/bin/Core/Debug/net10.0-android36.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.90-ci+azdo.14529355
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529355
  Maps -> /home/vsts/work/1/s/artifacts/bin/Maps/Debug/net10.0-android36.0/Microsoft.Maui.Maps.dll
  Controls.Core -> /home/vsts/work/1/s/artifacts/bin/Controls.Core/Debug/net10.0-android36.0/Microsoft.Maui.Controls.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529355
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529355
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529355
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529355
  Microsoft.AspNetCore.Components.WebView.Maui -> /home/vsts/work/1/s/artifacts/bin/Microsoft.AspNetCore.Components.WebView.Maui/Debug/net10.0-android36.0/Microsoft.AspNetCore.Components.WebView.Maui.dll
  Controls.Foldable -> /home/vsts/work/1/s/artifacts/bin/Controls.Foldable/Debug/net10.0-android36.0/Microsoft.Maui.Controls.Foldable.dll
  Controls.Maps -> /home/vsts/work/1/s/artifacts/bin/Controls.Maps/Debug/net10.0-android36.0/Microsoft.Maui.Controls.Maps.dll
  Controls.Xaml -> /home/vsts/work/1/s/artifacts/bin/Controls.Xaml/Debug/net10.0-android36.0/Microsoft.Maui.Controls.Xaml.dll
  Controls.TestCases.HostApp -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Controls.TestCases.HostApp.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529355
  Graphics -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Graphics.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529355
  Essentials -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Essentials.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529355
  Core -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529355
  Controls.BindingSourceGen -> /home/vsts/work/1/s/artifacts/bin/Controls.BindingSourceGen/Debug/netstandard2.0/Microsoft.Maui.Controls.BindingSourceGen.dll
  Maps -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Maps.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529355
  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.90-ci+azdo.14529355
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529355
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529355
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529355
  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
  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
  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:09:42.19
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...
  All projects are up-to-date for restore.
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529355
  Graphics -> /home/vsts/work/1/s/artifacts/bin/Graphics/Debug/net10.0/Microsoft.Maui.Graphics.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529355
  Essentials -> /home/vsts/work/1/s/artifacts/bin/Essentials/Debug/net10.0/Microsoft.Maui.Essentials.dll
  Controls.CustomAttributes -> /home/vsts/work/1/s/artifacts/bin/Controls.CustomAttributes/Debug/net10.0/Controls.CustomAttributes.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529355
  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.90-ci+azdo.14529355
  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
  UITest.Appium -> /home/vsts/work/1/s/artifacts/bin/UITest.Appium/Debug/net10.0/UITest.Appium.dll
  VisualTestUtils -> /home/vsts/work/1/s/artifacts/bin/VisualTestUtils/Debug/netstandard2.0/VisualTestUtils.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 1 of 1 NUnit test cases using Current Discovery mode, Non-Explicit run
>>>>> 06/30/2026 15:08:40 FixtureSetup for Issue35643(Android)
>>>>> 06/30/2026 15:08:42 CurrentItemShouldUpdateWhenCurrentItemIsReplaced Start
>>>>> 06/30/2026 15:08:46 CurrentItemShouldUpdateWhenCurrentItemIsReplaced Stop
  Passed CurrentItemShouldUpdateWhenCurrentItemIsReplaced [4 s]
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.64]   Discovered:  Controls.TestCases.Android.Tests
Results File: /home/vsts/work/1/s/CustomAgentLogsTmp/UITests/TestResults/Issue35643.trx

Test Run Successful.
Total tests: 1
     Passed: 1
 Total time: 23.6293 Seconds
>>> TRX_RESULT_FILE: /home/vsts/work/1/s/CustomAgentLogsTmp/UITests/TestResults/Issue35643.trx

📁 Fix files reverted (1 files)

  • src/Controls/src/Core/Handlers/Items/Android/MauiCarouselRecyclerView.cs

📱 UI Tests — CarouselView,CollectionView

Detected UI test categories: CarouselView,CollectionView

[!WARNING]
No UI test results were produced for the detected categories. The platform-pool run
returned no results — most often because the PR build failed (see the Gate section) or
the deep UI test stage was skipped. Fix the build/gate issues and comment /review rerun
to get UI test results.

📋 Pre-Flight — Context & Validation

Issue: #35643 - CurrentItem is updated incorrectly on Android when the CarouselView is bound to an ObservableCollection with Loop = false PR: #36243 - [WIP][Android] Fix for CurrentItem is updated incorrectly when the CarouselView is bound to an ObservableCollection with Loop = false Platforms Affected: Android Files Changed: 1 implementation, 2 test

Key Findings

Code Review Summary

Verdict: NEEDS_DISCUSSION Confidence: low Errors: 0 | Warnings: 2 | Suggestions: 1

Key code review findings:

  • src/Controls/src/Core/Handlers/Items/Android/MauiCarouselRecyclerView.cs:522-526 — loop-mode Replace only rebinds currently visible virtual positions; cached/prefetched virtual holders may remain stale.
  • src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue35643.cs:18 — test covers Loop = false only, while production fix adds substantial Loop = true behavior.
  • src/Controls/src/Core/Handlers/Items/Android/MauiCarouselRecyclerView.cs:442,468 — dispatch failure during teardown could leave _isInternalPositionUpdate set; current PR improves one guard but does not fully snapshot dispatcher state.

Fix Candidates

Source Approach Test Result Files Changed Notes

PR PR #36243 Dedicated Replace handler preserving position/current item; loop mode rebinds visible virtual cells ✅ PASSED (Gate, provided) MauiCarouselRecyclerView.cs, 2 UI test files Original PR; larger loop-mode surface than issue scenario
🔬 Code Review — Deep Analysis

Code Review — PR #36243

Independent Assessment

What this changes: Adds a dedicated Android CarouselView NotifyCollectionChangedAction.Replace path in MauiCarouselRecyclerView, preserving Position/CurrentItem instead of letting Replace fall through collection-update scroll-mode logic. It also adds an Android UI test for replacing the current item when Loop = false.

Inferred motivation: Avoid treating a Replace as removal of the old current item, which previously reset the carousel to position 0.

Reconciliation with PR Narrative

Author claims: Fixes Android issue 35643; regression from PR #26608; dedicated Replace path; loop mode handled by visible virtual-cell rebinding.

Agreement/disagreement: The non-loop root cause matches the code. The added loop-mode path is larger than the issue scenario and introduces new adapter-notification behavior that is not covered by the added test.

Prior Review Reconciliation

No prior ❌ Error findings found. Public API review surfaces showed no inline review comments and no review bodies; issue comments only had dogfood/review-request comments.

Blast Radius Assessment

  • Runs for all instances: Only Android CarouselView using observable item sources; Replace events now take a new branch.
  • Startup impact: No.
  • Static/shared state: No new static state.
  • Regression-sensitive area: Yes — Android CarouselView/RecyclerView adapter notification and loop virtualization.

CI Status

  • gh pr checks --required could not run because gh is unauthenticated.
  • Public check-runs API for head c7ecdb8…: 31 success, 3 in-progress, 1 queued, 1 skipped.
  • Classification: CI coverage pending/undetermined.
  • Confidence cap: low; cannot LGTM under the skill rules.

Findings

⚠️ Warning — Loop-mode Replace can leave non-visible cached virtual holders stale

File: src/Controls/src/Core/Handlers/Items/Android/MauiCarouselRecyclerView.cs:522-526

RebindVisibleLoopItem only calls NotifyItemChanged for positions between FindFirstVisibleItemPosition() and FindLastVisibleItemPosition(). In loop mode the adapter has 16,384 virtual positions, and Android RecyclerView may keep detached/prefetched holders outside the visible range. Those holders are not guaranteed to rebind when reattached unless their adapter position was notified. Concrete scenario: Loop = true, replace an item that has an off-screen cached virtual holder, then swipe to it; the cached holder can be reattached with the old binding context even though the underlying source changed.

This directly contradicts the new comment that “Off-screen cells … pick up the new value … when scrolled into view.” That is only true for newly-bound holders, not necessarily cached clean holders.

⚠️ Warning — Added test covers only Loop = false, but production change adds a new Loop = true path

File: src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue35643.cs:18

The regression test exercises the issue scenario with Loop = false, but HandleReplaceAction adds substantial behavior under Carousel.Loop (RebindVisibleLoopItem, modulo virtual positions, no ScrollToPosition). That branch is not covered. A loop-mode Replace regression could flash, jump, or show stale cells without this test failing.

💡 Suggestion — Replace branch should handle dispatcher/lifecycle failure symmetrically

File: src/Controls/src/Core/Handlers/Items/Android/MauiCarouselRecyclerView.cs:442 and :468

Both Replace branches call GetDispatcher().Dispatch(...) and rely on the dispatched finally to reset _isInternalPositionUpdate. If dispatch fails because the window/handler is tearing down, the flag can remain true. The existing code has similar risk, but this PR adds another path. Prefer snapshotting handler, mauiContext, and dispatcher, and if dispatch cannot be queued, reset _isInternalPositionUpdate synchronously.

Alternative Fix Directions

  1. Minimal root-cause fix: Keep Replace out of ItemsUpdatingScrollMode logic only. Apply scroll-mode overrides only for Add/Remove/Reset, then let the existing adapter Replace notification handle visual refresh. This avoids adding loop-specific virtual rebinding to fix a Loop = false bug.
  2. Adapter-level loop notification translation: If loop Replace must be fixed too, move virtual-position mapping closer to CarouselViewAdapter/adapter notifier so a real index Replace is translated consistently for attached/cached virtual positions, not just currently visible ones.
  3. Safe fallback for loop Replace: Use NotifyDataSetChanged() on the existing adapter for loop Replace rather than UpdateAdapter(). This avoids resetting Position/CurrentItem while invalidating cached holders broadly enough to prevent stale views.

Failure-Mode Probing

  • Replace current item, Loop = false: Current PR likely fixes the reported reset-to-0 behavior.
  • Replace current item, Loop = true: New branch is untested and relies on visible-only virtual notifications.
  • Replace off-screen item, Loop = true: Risk of stale cached holder because only visible positions are notified.
  • Handler teardown during Replace dispatch: Guard helps only before dispatch; dispatch failure can still leave _isInternalPositionUpdate set.

Verdict: NEEDS_DISCUSSION

Confidence: low Summary: The non-loop fix direction is sound, but the PR adds untested loop-mode adapter-notification logic in a fragile Android CarouselView path. I would either narrow the production change to the Loop = false root cause or add a robust loop-mode notification strategy plus Android regression coverage. CI is also still pending/undetermined from available public data.

🛠️ Fix — Analysis & Comparison

Fix Candidates

Source Approach Test Result Files Changed Notes

1 try-fix Minimal non-structural Replace handling; skip removal/scroll-mode/scroll-to for Replace ✅ UI test passed; ❌ expert comparison failed 1 file Simpler but worse than PR because it leaves Loop=true virtual-cell refresh unresolved
2 try-fix Dedicated Replace handler; loop mode uses existing adapter NotifyDataSetChanged() ✅ UI test passed; ❌ expert comparison failed 1 file Safer cached-holder invalidation but too broad/jank-prone versus PR's targeted rebind
3 try-fix Dedicated Replace handler; loop mode notifies matching virtual positions in a bounded viewport neighborhood ✅ UI test passed; ⚠ not demonstrably better 1 file Promising refinement, but unproven without Loop=true coverage and weaker fallback when layout state is unavailable
PR PR #36243 Dedicated Replace handler plus visible virtual-cell rebind for loop mode ✅ PASSED (Gate) 3 files Original PR; best-supported fix given available evidence, though loop-mode regression coverage would improve confidence

Cross-Pollination

Model Round New Ideas? Details
maui-expert-reviewer 1 Yes Candidate 1 must address loop-mode virtual adapter refresh.
maui-expert-reviewer 2 Yes Candidate 2 should avoid full adapter invalidation; try targeted virtual notifications that include current/cached window.
maui-expert-reviewer 3 No Remaining ideas are incremental hardening (candidate 3 fallback) or larger adapter/notifier architecture changes; neither is justified without new Loop=true tests.
Exhausted: Yes Selected Fix: PR #36243 — All three alternatives passed the available Android Issue35643 regression test, but none was demonstrably better than the PR fix. Candidate 1 missed loop-mode refresh, candidate 2 was too broad, and candidate 3's loop-mode advantage is unproven without additional tests.

Test Command Used For Candidates

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

📝 Recommended PR Title & Description

Assessment: ✏️ Recommend updating — the current description is strong, but the title still has a [WIP] prefix and the winning fix should mention the reviewer-added loop range/test coverage.

Recommended title

[Android] CarouselView: Preserve CurrentItem when replacing the selected item

Recommended description

### Issue details

The issue occurs on Android when replacing an item in the CarouselView.ItemsSource while Loop is set to false and simultaneously updating the CurrentItem. If the replaced item is the currently selected item, CarouselView incorrectly resets the selection to the first item instead of preserving the updated item as the current selection.

### Root Cause

When ItemsUpdatingScrollMode support was added to CarouselView collection change handling on Android, the change correctly implemented scroll-mode logic for Add, Remove, and Reset actions but did not add a dedicated path for the Replace action. This caused Replace to fall through into the KeepItemsInView/KeepLastItemInView scroll logic.

GetPosition(CurrentItem) always returns -1 after a Replace (old item gone from source), making removingCurrentElement = true and triggering a position reset to 0.

### Description of Change

The fix intercepts the Replace action at the top of CollectionItemsSourceChanged — before any Remove/Insert flags are computed — and delegates to a dedicated HandleReplaceAction method, ensuring Replace never reaches the KeepItemsInView reset logic.

For non-loop mode, SetCurrentItem and UpdatePosition are dispatched at the preserved position with no scroll. For loop mode, RebindVisibleLoopItem refreshes visible virtual cells that map to the replaced real index, avoiding a full adapter rebuild that previously caused a flash to position 0 and spurious events. The reviewer-enhanced fix also handles range Replace events by rebinding every replaced index and adds loop-mode regression coverage. All existing Remove, Reset, and Insert behavior is preserved.

### Regression PR

PR https://github.com/dotnet/maui/pull/26608

Tested the behavior in the following platforms.

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

### Issues Fixed

Fixes https://github.com/dotnet/maui/issues/35643

### Output

|Platform|Before|After|
|--|--|--|
|Android|<video src="https://github.com/user-attachments/assets/093a0324-9102-400f-944e-56a11565acc4"> |<video src="https://github.com/user-attachments/assets/08ebeb5c-59c3-4640-af15-530053c0cebb">|

🏁 Report — Final Recommendation

Comparative Report — PR #36243

Candidate ranking

Rank Candidate Regression result Assessment
1 pr-plus-reviewer Inherits PR gate pass; reviewer additions not independently run Best candidate. Preserves the PR's proven dedicated Replace path, keeps targeted loop rebind behavior, and addresses the expert reviewer's major test gap plus moderate range-Replace bug.
2 pr ✅ Gate passed Strong core fix for the reported Loop = false regression. Ranked below pr-plus-reviewer because expert review found untested loop-mode code and incomplete range Replace handling in that new loop path.
3 try-fix-3 ✅ UI test passed Strongest independent alternative in theory: targeted loop virtual-neighborhood notifications. Not demonstrably better than the PR because its advantage is untested and it removes the PR's conservative NotifyDataSetChanged() fallback when layout state is unavailable.
4 try-fix-2 ✅ UI test passed Correct for the proven non-loop regression but uses broad NotifyDataSetChanged() for loop Replace, increasing jank/rebind risk versus the PR's targeted visible-cell strategy.
5 try-fix-1 ✅ UI test passed Minimal and simple for Loop = false, but it leaves the loop-mode virtual-position refresh problem unresolved.

Comparison

All STEP 5a try-fix candidates passed the available Android Issue35643 regression test, and none failed regression testing. The gate rule therefore does not force any candidate below a failed candidate. The deciding factor is expert correctness coverage beyond the single tested non-loop scenario.

The raw PR fix is better than try-fix-1 because it handles the loop-mode virtual adapter-position mismatch instead of simply bypassing Replace scroll handling. It is better than try-fix-2 because it avoids a full adapter invalidation that can cause unnecessary jank and rebinding. It remains preferable to try-fix-3 because the PR keeps a conservative fallback to NotifyDataSetChanged() when layout state is unavailable, while candidate 3's bounded-neighborhood strategy is not covered by loop-mode tests.

pr-plus-reviewer wins because it is an incremental improvement to the best-supported approach rather than a replacement: it preserves the supplied gate-passing behavior, fixes the range Replace hole in the PR's loop branch, and adds the missing loop-mode regression coverage requested by the expert reviewer.

Winner

pr-plus-reviewer

🧭 Next Steps — review latest findings

I've reviewed the AI summary comments. Please find the following details.

  • Cached virtual holders stale: The ObservableCollection always fires single-item Replace events, so stale cached virtual holders are not a real concern for this bug. Adding it would cause a full rebind of all visible items in loop mode, introducing unnecessary jank.

  • No test for Loop = true: I have added a Loop = true carousel section in the host app and a new test CurrentItemShouldUpdateWhenCurrentItemIsReplacedInLoopMode covering the loop branch of HandleReplaceAction . Both tests pass locally on Android.

  • Dispatcher snapshot safety: The existing null guard at CollectionItemsSourceChanged entry already covers teardown. The dispatcher race is theoretical and not reproducible in the reported scenario.

@BagavathiPerumal BagavathiPerumal changed the title [WIP][Android] Fix for CurrentItem is updated incorrectly when the CarouselView is bound to an ObservableCollection with Loop = false [Android] Fix for CurrentItem is updated incorrectly when the CarouselView is bound to an ObservableCollection with Loop = false Jul 1, 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 1, 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 1, 2026
@kubaflo

kubaflo commented Jul 1, 2026

Copy link
Copy Markdown
Collaborator

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 3 pipeline(s).

@BagavathiPerumal

Copy link
Copy Markdown
Contributor Author

AI Review Summary

@BagavathiPerumal — new AI review results are available based on this last commit: d49dc86. 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: fa1d0d2d

Test Without Fix (expect FAIL) With Fix (expect PASS)
🖥️ Issue35643 Issue35643 ✅ FAIL — 1295s ✅ PASS — 720s
🔴 Without fix — 🖥️ Issue35643: FAIL ✅ · 1295s
(truncated to last 15,000 chars)

tored /home/vsts/work/1/s/src/Controls/src/Core/Controls.Core.csproj (in 6.78 sec).
  Restored /home/vsts/work/1/s/src/Controls/Maps/src/Controls.Maps.csproj (in 6.23 sec).
  Restored /home/vsts/work/1/s/src/Controls/Foldable/src/Controls.Foldable.csproj (in 140 ms).
  Restored /home/vsts/work/1/s/src/Essentials/src/Essentials.csproj (in 18 ms).
  Restored /home/vsts/work/1/s/src/Core/src/Core.csproj (in 53 ms).
  Restored /home/vsts/work/1/s/src/Core/maps/src/Maps.csproj (in 24 ms).
  Restored /home/vsts/work/1/s/src/BlazorWebView/src/Maui/Microsoft.AspNetCore.Components.WebView.Maui.csproj (in 1.44 sec).
  Restored /home/vsts/work/1/s/src/Controls/src/Xaml/Controls.Xaml.csproj (in 46 ms).
  Restored /home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj (in 1.35 sec).
  1 of 11 projects are up-to-date for restore.
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14541917
  Graphics -> /home/vsts/work/1/s/artifacts/bin/Graphics/Debug/net10.0-android36.0/Microsoft.Maui.Graphics.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14541917
  Essentials -> /home/vsts/work/1/s/artifacts/bin/Essentials/Debug/net10.0-android36.0/Microsoft.Maui.Essentials.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14541917
  Core -> /home/vsts/work/1/s/artifacts/bin/Core/Debug/net10.0-android36.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.90-ci+azdo.14541917
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14541917
  Maps -> /home/vsts/work/1/s/artifacts/bin/Maps/Debug/net10.0-android36.0/Microsoft.Maui.Maps.dll
  Controls.Core -> /home/vsts/work/1/s/artifacts/bin/Controls.Core/Debug/net10.0-android36.0/Microsoft.Maui.Controls.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14541917
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14541917
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14541917
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14541917
  Controls.Maps -> /home/vsts/work/1/s/artifacts/bin/Controls.Maps/Debug/net10.0-android36.0/Microsoft.Maui.Controls.Maps.dll
  Controls.Foldable -> /home/vsts/work/1/s/artifacts/bin/Controls.Foldable/Debug/net10.0-android36.0/Microsoft.Maui.Controls.Foldable.dll
  Microsoft.AspNetCore.Components.WebView.Maui -> /home/vsts/work/1/s/artifacts/bin/Microsoft.AspNetCore.Components.WebView.Maui/Debug/net10.0-android36.0/Microsoft.AspNetCore.Components.WebView.Maui.dll
  Controls.Xaml -> /home/vsts/work/1/s/artifacts/bin/Controls.Xaml/Debug/net10.0-android36.0/Microsoft.Maui.Controls.Xaml.dll
  Controls.TestCases.HostApp -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Controls.TestCases.HostApp.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14541917
  Graphics -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Graphics.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14541917
  Essentials -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Essentials.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14541917
  Core -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14541917
  Controls.BindingSourceGen -> /home/vsts/work/1/s/artifacts/bin/Controls.BindingSourceGen/Debug/netstandard2.0/Microsoft.Maui.Controls.BindingSourceGen.dll
  Maps -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Maps.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14541917
  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.90-ci+azdo.14541917
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14541917
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14541917
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14541917
  Controls.Foldable -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Controls.Foldable.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
  Controls.Maps -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Controls.Maps.dll
  Controls.Xaml -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Controls.Xaml.dll

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

Time Elapsed 00:09:17.30
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.27 sec).
  Restored /home/vsts/work/1/s/src/TestUtils/src/VisualTestUtils/VisualTestUtils.csproj (in 10 ms).
  Restored /home/vsts/work/1/s/src/TestUtils/src/VisualTestUtils.MagickNet/VisualTestUtils.MagickNet.csproj (in 6.31 sec).
  Restored /home/vsts/work/1/s/src/Controls/tests/TestCases.Android.Tests/Controls.TestCases.Android.Tests.csproj (in 7.84 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 4 ms).
  Restored /home/vsts/work/1/s/src/TestUtils/src/UITest.NUnit/UITest.NUnit.csproj (in 492 ms).
  Restored /home/vsts/work/1/s/src/TestUtils/src/UITest.Analyzers/UITest.Analyzers.csproj (in 2.5 sec).
  5 of 13 projects are up-to-date for restore.
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14541917
  Graphics -> /home/vsts/work/1/s/artifacts/bin/Graphics/Debug/net10.0/Microsoft.Maui.Graphics.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14541917
  Essentials -> /home/vsts/work/1/s/artifacts/bin/Essentials/Debug/net10.0/Microsoft.Maui.Essentials.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14541917
  Controls.CustomAttributes -> /home/vsts/work/1/s/artifacts/bin/Controls.CustomAttributes/Debug/net10.0/Controls.CustomAttributes.dll
  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.90-ci+azdo.14541917
  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
  VisualTestUtils.MagickNet -> /home/vsts/work/1/s/artifacts/bin/VisualTestUtils.MagickNet/Debug/netstandard2.0/VisualTestUtils.MagickNet.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
  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/01/2026 14:26:51 FixtureSetup for Issue35643(Android)
>>>>> 07/01/2026 14:30:48 The FixtureSetup threw an exception. Attempt 0/1.
Exception details: System.TimeoutException: CurrentItem is updated incorrectly on Android when the CarouselView is bound to an ObservableCollection with Loop = false (the app did not recover after crash-recovery attempts)
   at Microsoft.Maui.TestCases.Tests.UtilExtensions.WaitForGoToTestButtonWithRecovery(IApp app, String timeoutMessage) in /_/src/Controls/tests/TestCases.Shared.Tests/UtilExtensions.cs:line 91
   at Microsoft.Maui.TestCases.Tests._IssuesUITest.NavigateToIssue(String issue) in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/_IssuesUITest.cs:line 54
   at Microsoft.Maui.TestCases.Tests._IssuesUITest.TryToResetTestState() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/_IssuesUITest.cs:line 25
   at Microsoft.Maui.TestCases.Tests.UITest.FixtureSetup() in /_/src/Controls/tests/TestCases.Shared.Tests/UITest.cs:line 576
>>>>> 07/01/2026 14:30:51 FixtureSetup for Issue35643(Android)
>>>>> 07/01/2026 14:34:44 The FixtureSetup threw an exception. Attempt 1/1.
Exception details: System.TimeoutException: CurrentItem is updated incorrectly on Android when the CarouselView is bound to an ObservableCollection with Loop = false (the app did not recover after crash-recovery attempts)
   at Microsoft.Maui.TestCases.Tests.UtilExtensions.WaitForGoToTestButtonWithRecovery(IApp app, String timeoutMessage) in /_/src/Controls/tests/TestCases.Shared.Tests/UtilExtensions.cs:line 91
   at Microsoft.Maui.TestCases.Tests._IssuesUITest.NavigateToIssue(String issue) in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/_IssuesUITest.cs:line 54
   at Microsoft.Maui.TestCases.Tests._IssuesUITest.TryToResetTestState() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/_IssuesUITest.cs:line 25
   at Microsoft.Maui.TestCases.Tests.UITest.FixtureSetup() in /_/src/Controls/tests/TestCases.Shared.Tests/UITest.cs:line 576
>>>>> 07/01/2026 14:34:44 Log types: logcat, bugreport, server
>>>>> 07/01/2026 14:34:45 Log types: logcat, bugreport, server
  Failed CurrentItemShouldUpdateWhenCurrentItemIsReplaced [8 m 59 s]
  Error Message:
   OneTimeSetUp: System.TimeoutException : CurrentItem is updated incorrectly on Android when the CarouselView is bound to an ObservableCollection with Loop = false (the app did not recover after crash-recovery attempts)
  Stack Trace:
     at Microsoft.Maui.TestCases.Tests.UtilExtensions.WaitForGoToTestButtonWithRecovery(IApp app, String timeoutMessage) in /_/src/Controls/tests/TestCases.Shared.Tests/UtilExtensions.cs:line 91
   at Microsoft.Maui.TestCases.Tests._IssuesUITest.NavigateToIssue(String issue) in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/_IssuesUITest.cs:line 54
   at Microsoft.Maui.TestCases.Tests._IssuesUITest.TryToResetTestState() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/_IssuesUITest.cs:line 25
   at Microsoft.Maui.TestCases.Tests.UITest.FixtureSetup() in /_/src/Controls/tests/TestCases.Shared.Tests/UITest.cs:line 576
   at UITest.Appium.NUnit.UITestBase.OneTimeSetup() in /_/src/TestUtils/src/UITest.NUnit/UITestBase.cs:line 221
   at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
   at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)

  Failed CurrentItemShouldUpdateWhenCurrentItemIsReplacedInLoopMode [8 m 59 s]
  Error Message:
   OneTimeSetUp: System.TimeoutException : CurrentItem is updated incorrectly on Android when the CarouselView is bound to an ObservableCollection with Loop = false (the app did not recover after crash-recovery attempts)
  Stack Trace:
     at Microsoft.Maui.TestCases.Tests.UtilExtensions.WaitForGoToTestButtonWithRecovery(IApp app, String timeoutMessage) in /_/src/Controls/tests/TestCases.Shared.Tests/UtilExtensions.cs:line 91
   at Microsoft.Maui.TestCases.Tests._IssuesUITest.NavigateToIssue(String issue) in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/_IssuesUITest.cs:line 54
   at Microsoft.Maui.TestCases.Tests._IssuesUITest.TryToResetTestState() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/_IssuesUITest.cs:line 25
   at Microsoft.Maui.TestCases.Tests.UITest.FixtureSetup() in /_/src/Controls/tests/TestCases.Shared.Tests/UITest.cs:line 576
   at UITest.Appium.NUnit.UITestBase.OneTimeSetup() in /_/src/TestUtils/src/UITest.NUnit/UITestBase.cs:line 221
   at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
   at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)

Setup failed for test fixture Microsoft.Maui.TestCases.Tests.Issues.Issue35643(Android)
System.TimeoutException : CurrentItem is updated incorrectly on Android when the CarouselView is bound to an ObservableCollection with Loop = false (the app did not recover after crash-recovery attempts)
StackTrace:    at Microsoft.Maui.TestCases.Tests.UtilExtensions.WaitForGoToTestButtonWithRecovery(IApp app, String timeoutMessage) in /_/src/Controls/tests/TestCases.Shared.Tests/UtilExtensions.cs:line 91
   at Microsoft.Maui.TestCases.Tests._IssuesUITest.NavigateToIssue(String issue) in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/_IssuesUITest.cs:line 54
   at Microsoft.Maui.TestCases.Tests._IssuesUITest.TryToResetTestState() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/_IssuesUITest.cs:line 25
   at Microsoft.Maui.TestCases.Tests.UITest.FixtureSetup() in /_/src/Controls/tests/TestCases.Shared.Tests/UITest.cs:line 576
   at UITest.Appium.NUnit.UITestBase.OneTimeSetup() in /_/src/TestUtils/src/UITest.NUnit/UITestBase.cs:line 221
   at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
   at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)
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.22]   Discovering: Controls.TestCases.Android.Tests
[xUnit.net 00:00:00.85]   Discovered:  Controls.TestCases.Android.Tests
Results File: /home/vsts/work/1/s/CustomAgentLogsTmp/UITests/TestResults/Issue35643.trx

Test Run Failed.
Total tests: 2
     Failed: 2
 Total time: 9.2328 Minutes
>>> TRX_RESULT_FILE: /home/vsts/work/1/s/CustomAgentLogsTmp/UITests/TestResults/Issue35643.trx

🟢 With fix — 🖥️ Issue35643: PASS ✅ · 720s

  Determining projects to restore...
  All projects are up-to-date for restore.
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14541917
  Graphics -> /home/vsts/work/1/s/artifacts/bin/Graphics/Debug/net10.0-android36.0/Microsoft.Maui.Graphics.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14541917
  Essentials -> /home/vsts/work/1/s/artifacts/bin/Essentials/Debug/net10.0-android36.0/Microsoft.Maui.Essentials.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14541917
  Core -> /home/vsts/work/1/s/artifacts/bin/Core/Debug/net10.0-android36.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.90-ci+azdo.14541917
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14541917
  Maps -> /home/vsts/work/1/s/artifacts/bin/Maps/Debug/net10.0-android36.0/Microsoft.Maui.Maps.dll
  Controls.Core -> /home/vsts/work/1/s/artifacts/bin/Controls.Core/Debug/net10.0-android36.0/Microsoft.Maui.Controls.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14541917
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14541917
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14541917
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14541917
  Controls.Foldable -> /home/vsts/work/1/s/artifacts/bin/Controls.Foldable/Debug/net10.0-android36.0/Microsoft.Maui.Controls.Foldable.dll
  Controls.Xaml -> /home/vsts/work/1/s/artifacts/bin/Controls.Xaml/Debug/net10.0-android36.0/Microsoft.Maui.Controls.Xaml.dll
  Microsoft.AspNetCore.Components.WebView.Maui -> /home/vsts/work/1/s/artifacts/bin/Microsoft.AspNetCore.Components.WebView.Maui/Debug/net10.0-android36.0/Microsoft.AspNetCore.Components.WebView.Maui.dll
  Controls.Maps -> /home/vsts/work/1/s/artifacts/bin/Controls.Maps/Debug/net10.0-android36.0/Microsoft.Maui.Controls.Maps.dll
  Controls.TestCases.HostApp -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Controls.TestCases.HostApp.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14541917
  Graphics -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Graphics.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14541917
  Essentials -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Essentials.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14541917
  Core -> /home/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.90-ci+azdo.14541917
  Maps -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Maps.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14541917
  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.90-ci+azdo.14541917
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14541917
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14541917
  Controls.Foldable -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Controls.Foldable.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
  Controls.Xaml -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Controls.Xaml.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14541917
  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:09:17.48
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...
  All projects are up-to-date for restore.
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14541917
  Controls.CustomAttributes -> /home/vsts/work/1/s/artifacts/bin/Controls.CustomAttributes/Debug/net10.0/Controls.CustomAttributes.dll
  Graphics -> /home/vsts/work/1/s/artifacts/bin/Graphics/Debug/net10.0/Microsoft.Maui.Graphics.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14541917
  Essentials -> /home/vsts/work/1/s/artifacts/bin/Essentials/Debug/net10.0/Microsoft.Maui.Essentials.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14541917
  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.90-ci+azdo.14541917
  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
  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 -> /home/vsts/work/1/s/artifacts/bin/VisualTestUtils/Debug/netstandard2.0/VisualTestUtils.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/01/2026 14:46:32 FixtureSetup for Issue35643(Android)
>>>>> 07/01/2026 14:46:36 CurrentItemShouldUpdateWhenCurrentItemIsReplaced Start
>>>>> 07/01/2026 14:46:41 CurrentItemShouldUpdateWhenCurrentItemIsReplaced Stop
  Passed CurrentItemShouldUpdateWhenCurrentItemIsReplaced [5 s]
>>>>> 07/01/2026 14:46:41 CurrentItemShouldUpdateWhenCurrentItemIsReplacedInLoopMode Start
>>>>> 07/01/2026 14:46:46 CurrentItemShouldUpdateWhenCurrentItemIsReplacedInLoopMode Stop
  Passed CurrentItemShouldUpdateWhenCurrentItemIsReplacedInLoopMode [4 s]
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.50]   Discovered:  Controls.TestCases.Android.Tests
Results File: /home/vsts/work/1/s/CustomAgentLogsTmp/UITests/TestResults/Issue35643.trx

Test Run Successful.
Total tests: 2
     Passed: 2
 Total time: 31.5973 Seconds
>>> TRX_RESULT_FILE: /home/vsts/work/1/s/CustomAgentLogsTmp/UITests/TestResults/Issue35643.trx

📁 Fix files reverted (1 files)

  • src/Controls/src/Core/Handlers/Items/Android/MauiCarouselRecyclerView.cs

📱 UI Tests — CarouselView,CollectionView

Detected UI test categories: CarouselView,CollectionView

Deep UI tests — 683 passed, 27 failed across 2 categories on platform-pool agent (replaces in-process counts above).

🧪 UI Test Execution Results (deep, platform pool)

Category Tests Snapshot diffs
CarouselView 88/90 (2 ❌) 2 diff PNGs
CollectionView 595/620 (25 ❌) 2 diff PNGs
CarouselView — 2 failed tests

CollectionViewInsideCarouselViewShouldNotThrowIndexOutOfRangeException

System.TimeoutException : Timed out scrolling to Footer
at UITest.Appium.AppiumTouchActions.ScrollTo(IDictionary`2 parameters) in /_/src/TestUtils/src/UITest.Appium/Actions/AppiumTouchActions.cs:line 332
   at UITest.Appium.AppiumTouchActions.Execute(String commandName, IDictionary`2 parameters) in /_/src/TestUtils/src/UITest.Appium/Actions/AppiumTouchActions.cs:line 61
   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.ScrollTo(IApp app, String toElementId, Boolean down) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 716
   at Microsoft.Maui.TestCases.Tests.Issues.Issue31680.CollectionViewInsideCarouselViewShouldNotThrowIndexOutOfRangeException() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue31680.cs:line 35
   at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPt
...

VerticalCarouselMandatorySingleSnapAdvancesOneCard

VisualTestUtils.VisualTestFailedException : 
Snapshot different than baseline: VerticalCarouselMandatorySingleSnapAdvancesOneCard.png (4.87% difference)
If the correct baseline has changed (this isn't a a bug), then update the baseline image.
See test attachment or download the build artifacts to get the new snapshot file.

More info: https://aka.ms/visual-test-workflow
at Microsoft.Maui.TestCases.Tests.UITest.VerifyScreenshot(String name, Nullable`1 retryDelay, Nullable`1 retryTimeout, Int32 cropLeft, Int32 cropRight, Int32 cropTop, Int32 cropBottom, Double tolerance) in /_/src/Controls/tests/TestCases.Shared.Tests/UITest.cs:line 296
   at Microsoft.Maui.TestCases.Tests.Issues.Issue33308.VerticalCarouselMandatorySingleSnapAdvancesOneCard() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue33308.cs:line 26
   at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags
...

CollectionView — 25 failed tests

VisitAndUpdateItemsSource("Observable Collection","Add/RemoveItemsGrid",19,6)

The app was expected to be running still, investigate as possible crash
TearDown : The app was expected to be running still, investigate as possible crash
at UITest.Appium.NUnit.UITestBase.UITestBaseTearDown() in /_/src/TestUtils/src/UITest.NUnit/UITestBase.cs:line 159
   at UITest.Appium.NUnit.UITestBase.TestTearDown() in /_/src/TestUtils/src/UITest.NUnit/UITestBase.cs:line 45
   at InvokeStub_UITestBase.TestTearDown(Object, Object, IntPtr*)

--TearDown
   at UITest.Appium.NUnit.UITestBase.UITestBaseTearDown() in /_/src/TestUtils/src/UITest.NUnit/UITestBase.cs:line 159
   at UITest.Appium.NUnit.UITestBase.TestTearDown() in /_/src/TestUtils/src/UITest.NUnit/UITestBase.cs:line 45
   at InvokeStub_UITestBase.TestTearDown(Object, Object, IntPtr*)

1)    at UITest.Appium.NUnit.UITestBase.UITestBaseTearDown() in /_/src/TestUtils/src/UITest.NUnit/UITestBase.cs:line 159
   at UITest.Appium.NUnit.UITestBase.TestTearDown() in /_/src/TestUtils/src/UITest.NUnit/UITestBase.cs:line 45
   at InvokeS
...

VerifyGroupIndexScrollToByIndexWithEndPositionAndHorizontalGrid_Potato

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.CollectionView_ScrollingFeatureTests.VerifyGroupIndexScrollToByIndexWithEndPositionAndHorizontalGrid_Potato() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/CollectionView_ScrollingFeatureTests.cs:line 3170
   at System.Reflec
...

VerifyScrollToByItemWithCenterPositionAndHorizontalList_Kiwi

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.CollectionView_ScrollingFeatureTests.VerifyScrollToByItemWithCenterPositionAndHorizontalList_Kiwi() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/CollectionView_ScrollingFeatureTests.cs:line 2628
   at System.RuntimeMethodHan
...

VerifyGroupItemScrollToByIndexWithCenterPositionAndHorizontalList_Tomato

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.CollectionView_ScrollingFeatureTests.VerifyGroupItemScrollToByIndexWithCenterPositionAndHorizontalList_Tomato() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/CollectionView_ScrollingFeatureTests.cs:line 3453
   at System.Refl
...

VerifyFlowDirectionRTLWithHeaderTemplateAndFooterTemplateAndHorizontalGrid

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.CollectionView_SelectionFeatureTests.VerifyFlowDirectionRTLWithHeaderTemplateAndFooterTemplateAndHorizontalGrid() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/CollectionView_SelectionFeatureTests.cs:line 1182
   at System.Ru
...

VerifyGroupItemScrollToByIndexWithMakeVisiblePositionAndHorizontalList_Kiwi

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.CollectionView_ScrollingFeatureTests.VerifyGroupItemScrollToByIndexWithMakeVisiblePositionAndHorizontalList_Kiwi() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/CollectionView_ScrollingFeatureTests.cs:line 3241
   at System.R
...

VerifyScrollToByIndexWithStartPositionAndHorizontalList_Kiwi

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.CollectionView_ScrollingFeatureTests.VerifyScrollToByIndexWithStartPositionAndHorizontalList_Kiwi() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/CollectionView_ScrollingFeatureTests.cs:line 2214
   at System.RuntimeMethodHan
...

VerifyGroupItemScrollToByItemWithMakeVisiblePositionAndVerticalList_Apricot

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.CollectionView_ScrollingFeatureTests.VerifyGroupItemScrollToByItemWithMakeVisiblePositionAndVerticalList_Apricot() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/CollectionView_ScrollingFeatureTests.cs:line 1943
   at System.R
...

VerifyGroupItemScrollToByIndexWithEndPositionAndHorizontalGrid_Potato

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.CollectionView_ScrollingFeatureTests.VerifyGroupItemScrollToByIndexWithEndPositionAndHorizontalGrid_Potato() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/CollectionView_ScrollingFeatureTests.cs:line 3597
   at System.Reflect
...

VerifyGroupIndexScrollToByIndexWithCenterPositionAndVerticalList_Potato

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.CollectionView_ScrollingFeatureTests.VerifyGroupIndexScrollToByIndexWithCenterPositionAndVerticalList_Potato() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/CollectionView_ScrollingFeatureTests.cs:line 1874
   at System.Refle
...

VerifyGroupItemScrollToByItemWithCenterPositionAndVerticalList_Potato

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.CollectionView_ScrollingFeatureTests.VerifyGroupItemScrollToByItemWithCenterPositionAndVerticalList_Potato() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/CollectionView_ScrollingFeatureTests.cs:line 2007
   at System.Reflect
...

VerifyGroupItemScrollToByItemWithStartPositionAndVerticalList_Carrot

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.CollectionView_ScrollingFeatureTests.VerifyGroupItemScrollToByItemWithStartPositionAndVerticalList_Carrot() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/CollectionView_ScrollingFeatureTests.cs:line 1974
   at System.RuntimeM
...

VerifyGroupIndexScrollToByIndexWithStartPositionAndVerticalList_Carrot

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.CollectionView_ScrollingFeatureTests.VerifyGroupIndexScrollToByIndexWithStartPositionAndVerticalList_Carrot() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/CollectionView_ScrollingFeatureTests.cs:line 1838
   at System.Reflec
...

VerifyGroupItemScrollToByIndexWithEndPositionAndHorizontalList_Kiwi

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.CollectionView_ScrollingFeatureTests.VerifyGroupItemScrollToByIndexWithEndPositionAndHorizontalList_Kiwi() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/CollectionView_ScrollingFeatureTests.cs:line 3561
   at System.Reflectio
...

VerifyScrollToByItemWithMakeVisiblePositionAndHorizontalList_Kiwi

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.CollectionView_ScrollingFeatureTests.VerifyScrollToByItemWithMakeVisiblePositionAndHorizontalList_Kiwi() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/CollectionView_ScrollingFeatureTests.cs:line 2458
   at System.RuntimeMeth
...

VerifyGroupIndexScrollToByIndexWithMakeVisiblePositionAndVerticalList_Apricot

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.CollectionView_ScrollingFeatureTests.VerifyGroupIndexScrollToByIndexWithMakeVisiblePositionAndVerticalList_Apricot() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/CollectionView_ScrollingFeatureTests.cs:line 1802
   at System
...

VerifyGroupIndexScrollToByIndexWithCenterPositionAndHorizontalList_Tomato

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.CollectionView_ScrollingFeatureTests.VerifyGroupIndexScrollToByIndexWithCenterPositionAndHorizontalList_Tomato() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/CollectionView_ScrollingFeatureTests.cs:line 3026
   at System.Ref
...

VerifyScrollToByIndexWithEndPositionAndHorizontalList_Kiwi

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.CollectionView_ScrollingFeatureTests.VerifyScrollToByIndexWithEndPositionAndHorizontalList_Kiwi() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/CollectionView_ScrollingFeatureTests.cs:line 2376
   at System.RuntimeMethodHandl
...

VerifyScrollToByIndexWithMakeVisiblePositionAndHorizontalList_Kiwi

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.CollectionView_ScrollingFeatureTests.VerifyScrollToByIndexWithMakeVisiblePositionAndHorizontalList_Kiwi() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/CollectionView_ScrollingFeatureTests.cs:line 2137
   at System.RuntimeMet
...

VerifyGroupIndexScrollToByIndexWithEndPositionAndHorizontalList_Kiwi

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.CollectionView_ScrollingFeatureTests.VerifyGroupIndexScrollToByIndexWithEndPositionAndHorizontalList_Kiwi() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/CollectionView_ScrollingFeatureTests.cs:line 3134
   at System.Reflecti
...

VerifyScrollToByIndexWithCenterPositionAndHorizontalList_Kiwi

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.CollectionView_ScrollingFeatureTests.VerifyScrollToByIndexWithCenterPositionAndHorizontalList_Kiwi() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/CollectionView_ScrollingFeatureTests.cs:line 2295
   at System.RuntimeMethodHa
...

VerifyScrollToByItemWithEndPositionAndHorizontalList_Kiwi

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.CollectionView_ScrollingFeatureTests.VerifyScrollToByItemWithEndPositionAndHorizontalList_Kiwi() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/CollectionView_ScrollingFeatureTests.cs:line 2715
   at System.RuntimeMethodHandle
...

VerifyGroupIndexScrollToByIndexWithMakeVisiblePositionAndHorizontalList_Kiwi

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.CollectionView_ScrollingFeatureTests.VerifyGroupIndexScrollToByIndexWithMakeVisiblePositionAndHorizontalList_Kiwi() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/CollectionView_ScrollingFeatureTests.cs:line 2810
   at System.
...

VerifyGroupItemScrollToByIndexWithStartPositionAndHorizontalList_Kiwi

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.CollectionView_ScrollingFeatureTests.VerifyGroupItemScrollToByIndexWithStartPositionAndHorizontalList_Kiwi() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/CollectionView_ScrollingFeatureTests.cs:line 3345
   at System.Reflect
...

VerifyGroupIndexScrollToByIndexWithStartPositionAndHorizontalList_Kiwi

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.CollectionView_ScrollingFeatureTests.VerifyGroupIndexScrollToByIndexWithStartPositionAndHorizontalList_Kiwi() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/CollectionView_ScrollingFeatureTests.cs:line 2918
   at System.Reflec
...

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

📋 Pre-Flight — Context & Validation

Issue: #35643 - CurrentItem is updated incorrectly on Android when the CarouselView is bound to an ObservableCollection with Loop = false PR: #36243 - [Android] Fix for CurrentItem is updated incorrectly when the CarouselView is bound to an ObservableCollection with Loop = false Platforms Affected: Android Files Changed: 1 implementation, 2 test

Key Findings

  • The bug is a regression in Android CarouselView collection-change handling: Replace events fall through ItemsUpdatingScrollMode logic and can reset Position/CurrentItem to 0 when the old CurrentItem is no longer found.
  • The PR's fix adds a dedicated Replace path in MauiCarouselRecyclerView.CollectionItemsSourceChanged, preserving position and updating CurrentItem without scrolling; loop mode rebinds matching visible virtual cells.
  • Prior MauiBot findings about range Replace in loop mode and missing loop tests appear addressed in the current PR diff.
  • GitHub CLI auth is unavailable in this environment, so PR/issue context was gathered from public REST API and local review branch state.

Code Review Summary

Verdict: NEEDS_DISCUSSION Confidence: low Errors: 0 | Warnings: 1 | Suggestions: 2

Key code review findings:

  • ⚠ Missing coverage for non-current Replace in src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue35643.cs:16.
  • ℹ Consider returning early instead of NotifyDataSetChanged() when loop mode has no visible positions in MauiCarouselRecyclerView.cs:522-525.
  • ℹ Consider text-specific waits after taps in the UI test to reduce Appium timing flakiness.

Fix Candidates

Source Approach Test Result Files Changed Notes

PR PR #36243 Dedicated Android CarouselView Replace handler preserves position/current item and rebinds visible loop virtual cells. ✅ PASSED (Gate) MauiCarouselRecyclerView.cs, Issue35643.cs host/test Original PR
🔬 Code Review — Deep Analysis

Code Review — PR #36243

Independent Assessment

What this changes: Android CarouselView now treats NotifyCollectionChangedAction.Replace as position-preserving instead of letting it fall through the add/remove scroll-mode path. Loop mode additionally rebinds visible virtual cells without rebuilding the adapter. Inferred motivation: Replacing items in an ObservableCollection could reset CurrentItem/Position to 0, especially with default KeepItemsInView.

Reconciliation with PR Narrative

Author claims: Fixes Android CarouselView CurrentItem reset on Replace; preserves existing add/remove/reset behavior; adds Android UI tests. Agreement/disagreement: Matches the code. The dedicated Replace path avoids the root cause described. The loop-mode handling is broader than the title but is consistent with preserving Replace behavior.

Prior Review Reconciliation

No prior ❌ Error findings found.

Prior non-error findings checked:

  • MauiBot [moderate] multi-item loop Replace stale-cell concern: ✅ Fixed; current code iterates replaceCount at MauiCarouselRecyclerView.cs:442-446.
  • MauiBot [major] missing loop-mode test: ✅ Fixed; loop test exists at Issue35643.cs:32-48.

Blast Radius Assessment

  • Runs for all instances: No; only Android CarouselView collection-change Replace path.
  • Startup impact: No.
  • Static/shared state: No.
  • Handler/platform hot path: Yes; Android RecyclerView adapter notifications and CarouselView position synchronization. Confidence capped at medium, then CI caps lower.

CI Status

  • Required-check result: gh pr checks --required unavailable due missing GitHub auth. Public check-runs show maui-pr has one failed leg and several pending/in-progress checks.
  • Classification: failed leg appears infrastructure/network-related (dotnet-install.ps1 SSL/LSA download failure), but CI remains pending/undetermined overall.
  • Action taken: CI confidence capped at low; verdict cannot be LGTM from code review alone.

Findings

⚠️ Warning — Missing coverage for non-current Replace

src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue35643.cs:16

The tests cover replacing the current item in loop and non-loop modes, but the implementation fixes every Replace event. The old fallthrough could also reset position when replacing a non-current item under default KeepItemsInView. Add a case replacing index 0 while current position remains 2.

💡 Suggestion — Avoid full invalidation when no visible loop cells exist

src/Controls/src/Core/Handlers/Items/Android/MauiCarouselRecyclerView.cs:522-525

When FindFirstVisibleItemPosition() or FindLastVisibleItemPosition() returns NoPosition, there are no visible holders to rebind. Returning early would avoid an unnecessary NotifyDataSetChanged().

💡 Suggestion — Wait for updated label text in UI tests

src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue35643.cs:26 and :44

After tapping, the tests immediately read label text. A text-specific wait would reduce Appium timing flakiness.

Failure-Mode Probing

  • Replace during teardown/null handler: entry guard resets _isInternalPositionUpdate and returns.
  • Explicit ScrollTo races with delayed Replace callback: _scrollToCounter prevents stale callback from overriding explicit scroll.
  • Loop mode virtual positions: visible virtual positions matching changedIndex are rebound; off-screen cells bind fresh when recycled.
  • Multi-item Replace: current code iterates the replaced range.
  • Background collection change: ObservableItemsSource dispatches collection handling through the container dispatcher before invoking this handler.

Verdict: NEEDS_DISCUSSION

Confidence: low Summary: The code approach looks sound and prior non-error findings appear addressed. However, CI is still failed/pending/undetermined, and there is a meaningful non-current Replace coverage gap, so this should not be marked LGTM yet.

🛠️ Fix — Analysis & Comparison

Fix Candidates

Source Approach Test Result Files Changed Notes

1 MAUI expert reviewer Treat Replace as non-structural; preserve position/current item; loop mode uses NotifyDataSetChanged() full refresh. ✅ PASS 1 file Passed 2/2 Android UI tests; simpler but less precise and potentially more visually disruptive than PR.
2 MAUI expert reviewer + failure learning Return early for Replace before removal/scroll-mode logic; rely on app's explicit CurrentItem binding update. ✅ PASS 1 file Passed 2/2 Android UI tests; self-review found under-complete collection-only Replace and loop visual-refresh gaps.
3 MAUI expert reviewer + failure learning Move loop item/range refresh into CarouselViewAdapter notifier; recycler view only preserves Replace position/current item. ✅ PASS 2 files Initial compile failed (CS0030 generic cast), fixed and passed 2/2 Android UI tests; broader blast radius and full invalidation in loop hot paths.
PR PR #36243 Dedicated Android CarouselView Replace handler preserves position/current item and surgically rebinds matching visible loop virtual cells. ✅ PASSED (Gate) 3 files Original PR; most targeted robust fix among tested approaches.

Cross-Pollination

Model/Reviewer Round New Ideas? Details
maui-expert-reviewer 1 Yes Proposed full loop refresh, adapter-notification-layer handling, and CurrentItem-driven reconciliation.
iterative test loop 2 Yes Candidate 3 incorporated Candidate 1's loop full-refresh learning but moved it to adapter notification; compile failure fed back into the same attempt and was corrected.
final expert comparison 2 No Remaining variations were trivial combinations of tested approaches: targeted rebind (PR), full refresh (candidate 1/3), or no-op/rely-on binding (candidate 2).

Candidate Narratives

try-fix-1

See ../try-fix-1/content.md.

Summary: ✅ PASS. The full-refresh loop strategy proves that treating Replace as non-structural fixes the gate, but it is not demonstrably better than the PR because it broadens loop refresh to NotifyDataSetChanged().

try-fix-2

See ../try-fix-2/content.md.

Summary: ✅ PASS. The minimal no-op strategy proves the exact repro is fixed by avoiding the removal/scroll-mode path, but expert self-review found it relies on a subsequent app CurrentItem setter and can leave loop visuals stale.

try-fix-3

See ../try-fix-3/content.md.

Summary: ✅ PASS after one compile-fix iteration. The adapter-layer strategy is viable but broader, touches more files, and uses full invalidation for loop item/range changes.

Exhausted: Yes Selected Fix: PR #36243 — The PR's current fix is the best option: it passes the gate, is more complete than candidate 2, more localized than candidate 3, and more precise/performance-safe than candidate 1's full adapter refresh.

🏁 Report — Final Recommendation

Comparative Report — PR #36243

Candidate ranking

Rank Candidate Regression result Assessment
1 pr ✅ Gate passed Best candidate. It directly handles Replace before remove/scroll-mode logic, preserves Position/CurrentItem, includes loop-mode visible virtual-cell rebinding, handles range Replace, and includes Android UI coverage for both non-loop and loop cases.
2 pr-plus-reviewer ✅ Inherits PR gate pass Equivalent to pr because the expert reviewer found no actionable feedback to apply. Ranked below pr only because it introduces no distinct improvement over the submitted fix.
3 try-fix-1 ✅ PASS Correctly treats Replace as non-structural and preserves position, but loop mode uses broad NotifyDataSetChanged(), which is less targeted and potentially more visually disruptive than the PR's visible virtual-cell rebind.
4 try-fix-3 ✅ PASS after compile-fix iteration Viable adapter-layer strategy, but broader in blast radius: it changes CarouselViewAdapter notification behavior and uses full adapter invalidation for loop item/range changes.
5 try-fix-2 ✅ PASS Minimal and fixes the narrow gate scenario by returning early for Replace, but it relies on a separate app CurrentItem setter and can leave collection-only Replace and loop virtual-cell refresh incomplete.

Comparison

All candidates passed their available regression tests, so no candidate is forced below another by a failed regression result. The deciding factors are completeness, blast radius, visual stability, and how well each approach handles CarouselView loop-mode virtual positions.

The raw PR fix is the strongest option because it addresses the root cause without changing adapter-wide notification behavior. It prevents Replace from flowing into ItemsUpdatingScrollMode reset logic, refreshes CurrentItem from the preserved position, and avoids scroll jumps. Its loop-mode branch is more precise than try-fix-1 and try-fix-3 because it rebinds only visible virtual cells that map to replaced real indices, while retaining safe fallback full refreshes when layout state is unavailable.

pr-plus-reviewer does not supersede the PR because the expert reviewer produced no actionable findings and no code changes were applied in the sandbox copy. It is therefore functionally identical to pr.

try-fix-1 proves that treating Replace as non-structural is enough to pass the regression, but its full loop refresh is less performance-safe. try-fix-3 is also valid but broadens the change to adapter notification plumbing, increasing regression surface. try-fix-2 is the smallest change but is under-complete outside the exact app-driven repro because it depends on an explicit CurrentItem update and does not refresh loop virtual cells.

Winner

pr

The submitted PR fix wins because it is the most complete and targeted gate-passing implementation, and expert review found no additional actionable changes to apply.

🧭 Next Steps — review latest findings

The test failures mentioned in the AI summary are not present in the latest CI run. The only remaining CollectionView-related failure reported in the latest CI could not be reproduced locally and is not related to this fix.

… -1 when an unequal-count Replace operation empties the collection. This prevents an invalid negative position from being passed to UpdatePosition and ScrollToPosition, ensuring a valid carousel state.
Copilot AI review requested due to automatic review settings July 15, 2026 11:21

Copilot AI 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.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

@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 15, 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.

@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

@BagavathiPerumal — new AI review results are available based on this last commit: 2ea358c. 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)
🖥️ Issue35643 Issue35643 ✅ FAIL — 2522s ✅ PASS — 586s
🔴 Without fix — 🖥️ Issue35643: FAIL ✅ · 2522s

Error-relevant lines (filtered from the build log):

/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010: Mono.AndroidTools.InstallFailedException: Unexpected install output: cmd: Failure calling service package: Broken pipe (32) [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010:  [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010:    at Mono.AndroidTools.Internal.AdbOutputParsing.CheckInstallSuccess(String output, String packageName) [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010:    at Mono.AndroidTools.AndroidDevice.<>c__DisplayClass105_0.<InstallPackage>b__0(Task`1 t) [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010:    at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state) [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010: --- End of stack trace from previous location --- [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010:    at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot, Thread threadPoolThread) [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010:    at AndroidDeviceExtensions.PushAndInstallPackageAsync(AndroidDevice device, PushAndInstallCommand command, CancellationToken token) [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010:    at Xamarin.Android.Tasks.FastDeploy.InstallPackage(Boolean installed) [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010:    at Xamarin.Android.Tasks.FastDeploy.RunInstall() [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
Build FAILED.
     at Microsoft.Maui.TestCases.Tests.Issues.Issue35643.CurrentItemShouldUpdateWhenCurrentItemIsReplaced() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue35643.cs:line 31
     at Microsoft.Maui.TestCases.Tests.Issues.Issue35643.CurrentItemShouldUpdateWhenCurrentItemIsReplacedInLoopMode() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue35643.cs:line 56
🟢 With fix — 🖥️ Issue35643: PASS ✅ · 586s

(no coded error found; showing last 1200 chars)

Tests.dll
   NUnit3TestExecutor discovered 2 of 2 NUnit test cases using Current Discovery mode, Non-Explicit run
>>>>> 07/15/2026 16:25:39 FixtureSetup for Issue35643(Android)
>>>>> 07/15/2026 16:25:42 CurrentItemShouldUpdateWhenCurrentItemIsReplaced Start
>>>>> 07/15/2026 16:25:48 CurrentItemShouldUpdateWhenCurrentItemIsReplaced Stop
  Passed CurrentItemShouldUpdateWhenCurrentItemIsReplaced [6 s]
>>>>> 07/15/2026 16:25:49 CurrentItemShouldUpdateWhenCurrentItemIsReplacedInLoopMode Start
>>>>> 07/15/2026 16:25:53 CurrentItemShouldUpdateWhenCurrentItemIsReplacedInLoopMode Stop
  Passed CurrentItemShouldUpdateWhenCurrentItemIsReplacedInLoopMode [4 s]
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.50]   Discovered:  Controls.TestCases.Android.Tests
Results File: /home/vsts/work/1/s/CustomAgentLogsTmp/UITests/TestResults/Issue35643.trx

Test Run Successful.
Total tests: 2
     Passed: 2
 Total time: 25.4401 Seconds
>>> TRX_RESULT_FILE: /home/vsts/work/1/s/CustomAgentLogsTmp/UITests/TestResults/Issue35643.trx

📁 Fix files reverted (1 files)
  • src/Controls/src/Core/Handlers/Items/Android/MauiCarouselRecyclerView.cs

📱 UI Tests — CarouselView,CollectionView

Detected UI test categories: CarouselView,CollectionView

⚠️ Deep UI tests — The deep UI run for 2 categories (CarouselView, CollectionView) was interrupted before producing results — most often the per-category time budget (a very long-running category) was exhausted, or an emulator/Appium hang. This is usually an infrastructure/timeout issue rather than a code problem; re-run the review to try again. See the build-output.log in the drop-deep-uitests artifact.


📋 Pre-Flight — Context & Validation

Issue: #35643 - CurrentItem is updated incorrectly on Android when the CarouselView is bound to an ObservableCollection with Loop = false
PR: #36243 - [Android] Fix for CurrentItem is updated incorrectly when the CarouselView is bound to an ObservableCollection with Loop = false
Platforms Affected: Android
Files Changed: 1 implementation, 2 test

Key Findings

  • Issue #35643 is a verified Android regression introduced in 9.0.60: replacing the currently selected CarouselView item while also updating CurrentItem resets Android non-loop selection to item 0 instead of the replacement item.
  • PR #36243 adds a dedicated Android equal-count Replace path in MauiCarouselRecyclerView.CollectionItemsSourceChanged, plus UI tests for loop and non-loop CarouselView replacement.
  • The PR's implementation avoids falling through to removal/scroll-mode logic and includes loop-mode visible virtual-cell rebinding, but code review found a deferred-dispatch teardown race in the new callbacks.

Code Review Summary

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

Key code review findings:

  • src/Controls/src/Core/Handlers/Items/Android/MauiCarouselRecyclerView.cs:568 and :606 — dispatched Replace callbacks can run after handler teardown and dereference Carousel through SetCurrentItem, UpdatePosition, or UpdateVisualStates without revalidating lifecycle state.
  • src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue35643.cs — tests cover the main equal-count single-item Replace path, but not adjacent unequal-count, indexless Replace, or teardown/disconnect safety branches.

Fix Candidates

# Source Approach Test Result Files Changed Notes
PR PR #36243 Dedicated Android equal-count Replace handler preserving position/current item, plus loop-mode visible virtual-cell rebind without adapter rebuild ✅ PASSED (Gate) src/Controls/src/Core/Handlers/Items/Android/MauiCarouselRecyclerView.cs, src/Controls/tests/TestCases.HostApp/Issues/Issue35643.cs, src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue35643.cs Original PR; gate result supplied by caller

🔬 Code Review — Deep Analysis

Code Review — PR #36243

Independent Assessment

What this changes: Adds Android CarouselView handling for equal-count NotifyCollectionChangedAction.Replace, preserving Position/CurrentItem and rebinding visible loop-mode virtual cells without a full adapter rebuild. Adds Android UI coverage for loop and non-loop replacement.

Inferred motivation: Replacing the selected item currently looks like removal because the old CurrentItem no longer exists, causing position/current item reset behavior.

Reconciliation with PR Narrative

Author claims: Android-only fix for issue #35643; preserves replace position/current item, with special loop-mode virtual-cell refresh.
Agreement/disagreement: The intent matches the code. However, the new dispatched callbacks still have handler teardown races despite the PR’s lifecycle guard.

Prior Review Reconciliation

No prior ❌ Error findings found.

Notable prior [major]/[moderate] findings were mostly addressed:

  • Missing loop-mode test: ✅ fixed.
  • Range replace rebind: ✅ fixed.
  • Unequal replace clamp: ✅ fixed.
  • Indexless replace: ✅ mostly addressed.
  • Latest UI-thread adapter-notification comments: likely obsolete because ObservableItemsSource.CollectionChanged dispatches via _container.Dispatcher.DispatchIfRequired(...) before raising CollectionItemsSourceChanged.

Blast Radius Assessment

  • Runs for all instances: No; only Android CarouselView collection changes.
  • Startup impact: No.
  • Static/shared state: No.
  • Handler/platform plumbing: Yes — confidence capped at medium, then CI red caps to low.

CI Status

  • Required-check result: gh pr checks --required unavailable due unauthenticated gh; fallback GitHub Checks API shows maui-pr failed.
  • Classification: CI failure appears PR-unrelated infra. AzDO build 1510132 failed in RunOniOS_BlazorDebug ARM64 because Install Simulator Runtimes timed out while downloading iOS 26.0 simulator; unrelated to Android CarouselView code.
  • Action taken: Invoked azdo-build-investigator; confidence capped low because CI is red/tool fallback was required.

Findings

❌ Error — Deferred Replace callbacks can still run after handler teardown

CollectionItemsSourceChanged guards Carousel?.Handler?.MauiContext before entering HandleReplaceAction, but both new dispatcher callbacks dereference Carousel later without revalidating lifecycle state.

Affected lines:

  • src/Controls/src/Core/Handlers/Items/Android/MauiCarouselRecyclerView.cs:568
  • src/Controls/src/Core/Handlers/Items/Android/MauiCarouselRecyclerView.cs:606

If TearDownOldElement/handler disconnect happens after Dispatch(...) queues but before the callback executes, ItemsView/Carousel can be null. Then SetCurrentItem, UpdatePosition, or UpdateVisualStates can throw. Re-check Carousel?.Handler?.MauiContext inside each dispatched lambda before touching carousel state, while still resetting _isInternalPositionUpdate/_noNeedForScroll in finally.

⚠️ Warning — Adjacent Replace edge cases remain untested

The tests cover the main equal-count single-item replace path, including loop mode visible-cell rebind. They do not cover adjacent branches added by this PR: unequal-count replace clamping, indexless replace fallback, or teardown/disconnect safety. Given the handler complexity, at least one lighter adjacent test would reduce regression risk.

Failure-Mode Probing

  • Handler disconnect after dispatch: currently unsafe; callback can dereference Carousel after teardown.
  • Dispatch refuses to queue: flags are reset; handled.
  • Empty collection after unequal replace: clamped to 0; avoids ScrollToPosition(-1).
  • Multi-item equal replace in loop mode: iterates replaced range; addressed.
  • Background collection change: ObservableItemsSource marshals via dispatcher before raising this handler event.

Verdict: NEEDS_CHANGES

Confidence: low
Summary: The fix addresses the reported behavior and prior review concerns, but the new deferred callbacks still have a concrete Android handler lifecycle race. CI is also currently red, though the observed failure appears infrastructure-related rather than PR-caused.


🛠️ Fix — Analysis & Comparison

Fix Candidates

# Source Approach Test Result Files Changed Notes
1 try-fix-1 / maui-expert-reviewer Synchronous count-preserving Replace reconciliation; no deferred dispatch; NotifyDataSetChanged() only for loop-mode virtual cell refresh ✅ PASS 1 file Simpler than PR fix and eliminates the lifecycle race found in pre-flight review
PR PR #36243 Dedicated equal-count Replace handler with deferred callbacks and targeted visible loop virtual-cell rebind ✅ PASSED (Gate) 3 files Original PR; gate result supplied by caller

Cross-Pollination

Model Round New Ideas? Details
maui-expert-reviewer 1 Yes Proposed synchronous count-preserving Replace reconciliation as a different root-cause/implementation approach

Exhausted: No — stopped after Candidate #1 because it passed the Android regression tests and is demonstrably simpler while removing the PR fix's deferred-callback lifecycle race.
Selected Fix: Candidate #1 — passes the same target tests, changes only the Android implementation file, removes the queued dispatch teardown hazard, and has a substantially smaller implementation. Tradeoff: loop-mode refresh is coarser than the PR's targeted virtual-cell notification.

Environment notes: gh is unauthenticated in this environment, so GitHub CLI PR queries were replaced with public GitHub API reads. EstablishBrokenBaseline.ps1 could not establish a broken baseline because the repository already contained unrelated dirty .github/eng files; the attempt continued by changing only src/Controls/src/Core/Handlers/Items/Android/MauiCarouselRecyclerView.cs and capturing the diff separately.


📝 Recommended PR Title & Description

Assessment: ✏️ Recommend updating — the current description is strong, but the winning fix adds deferred-callback lifecycle revalidation that is not reflected, and the title can be made shorter and more component-focused.

Recommended title

[Android] CarouselView: Preserve CurrentItem when replacing the selected item

Recommended description

### Issue details

The issue occurs on Android when replacing an item in the CarouselView.ItemsSource while Loop is set to false and simultaneously updating the CurrentItem. If the replaced item is the currently selected item, CarouselView incorrectly resets the selection to the first item instead of preserving the updated item as the current selection.

### Root Cause

When ItemsUpdatingScrollMode support was added to CarouselView collection change handling on Android, the change correctly implemented scroll-mode logic for Add, Remove, and Reset actions but did not add a dedicated path for the Replace action. This caused Replace to fall through into the KeepItemsInView/KeepLastItemInView scroll logic.

GetPosition(CurrentItem) always returns -1 after a Replace (old item gone from source), making removingCurrentElement = true and triggering a position reset to 0.

### Description of Change

The fix involves intercepting the Replace action at the top of CollectionItemsSourceChanged — before any Remove/Insert flags are computed — and delegating to a dedicated HandleReplaceAction method, ensuring Replace never reaches the KeepItemsInView reset logic.

For non-loop mode, SetCurrentItem and UpdatePosition are dispatched at the preserved position with no scroll. For loop mode, a new RebindVisibleLoopItem helper surgically rebinds only the visible virtual cells that map to the replaced real index, avoiding a full adapter rebuild that previously caused a flash to position 0 and spurious events. The deferred Replace callbacks also re-check Carousel.Handler.MauiContext before applying state updates so handler teardown between dispatch and callback execution does not dereference a disconnected CarouselView. All existing Remove, Reset, and Insert behavior is fully preserved.

The Android UI tests cover both Loop=false and Loop=true replacement. The loop-mode test verifies the visible carousel cell is rebound to the replacement item and scrolls the LoopCarouselView back into view before querying the cell AutomationId so RecyclerView does not recycle the target cell off-screen.

### Regression PR

PR https://github.com/dotnet/maui/pull/26608

Tested the behavior in the following platforms.

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

### Issues Fixed

Fixes https://github.com/dotnet/maui/issues/35643

### Output

|Platform|Before|After|
|--|--|--|
|Android|<video src="https://github.com/user-attachments/assets/093a0324-9102-400f-944e-56a11565acc4"> |<video src="https://github.com/user-attachments/assets/08ebeb5c-59c3-4640-af15-530053c0cebb">|

🏁 Report — Final Recommendation

Comparative Report — PR #36243

Candidates compared

Rank Candidate Regression result Assessment
1 pr-plus-reviewer Not separately re-run; preserves the raw PR's passing regression path and only adds lifecycle guards inside the new Replace callbacks plus a test scroll-back before asserting the visible loop cell Best overall. Keeps the PR's comprehensive equal-count Replace handling, loop-mode targeted visible-cell rebind, and Android UI tests, while fixing the actionable deferred-dispatch teardown race and small-screen test reliability issue.
2 try-fix-1 ✅ PASS Strong alternative. Simpler synchronous count-preserving Replace reconciliation removes the deferred callback race entirely and passed the Issue35643 Android UI tests. Ranked below pr-plus-reviewer because it is coarser for loop mode (NotifyDataSetChanged) and only handles equal-count Replace when the current position is inside the replaced range, whereas the PR path consistently short-circuits equal-count Replace and preserves current carousel state.
3 pr ✅ PASSED gate Functionally addresses the reported regression and includes good UI coverage, but remains below the other passing candidates because expert review identified an actionable lifecycle race in the newly queued Replace callbacks and a loop-mode test reliability issue after scrolling to the button.

No candidate failed the supplied regression gate. Per the ranking rule, a regression-failing candidate would be ranked below all passing candidates; that condition did not apply here.

Winning candidate

pr-plus-reviewer

Rationale

The raw PR fix correctly identifies the root cause: Android equal-count Replace was falling through into removal / scroll-mode logic because the old CurrentItem no longer exists in the source. pr-plus-reviewer preserves that fix and the PR's loop-mode virtual-cell rebind strategy, while applying the expert reviewer's concrete lifecycle feedback by re-checking Carousel?.Handler?.MauiContext inside each deferred Replace callback before touching carousel state. It also applies the reviewer test feedback by scrolling LoopCarouselView back into view before asserting the visible rebound cell.

Compared with try-fix-1, pr-plus-reviewer has slightly more implementation complexity, but it retains the PR's more precise loop-mode updates and broader equal-count Replace handling. The added reviewer changes are surgical and do not alter the successful regression behavior except in unsafe/disconnected handler states or when stabilizing the UI test's visibility precondition.


🧭 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 pushed a commit that referenced this pull request Jul 15, 2026
The deep UI test loop previously bounded itself at a 210-min internal hard
stop under a 220-min AzDO task timeout / 240-min job timeout. For heavy,
genuinely long-running categories (e.g. CarouselView + CollectionView on
PR #36243, or a lone ~391-test CollectionView) the per-category fair-share
slice was too small — two heavy categories got only ~105 min each and were
cut off mid-run, then mis-reported as an infra timeout ("interrupted before
producing results").

Raise the whole budget stack to the Microsoft-hosted-agent maximum (a
360-min per-job ceiling that Android/Windows Azure-Pipelines agents cannot
exceed):

  - deep JOB timeoutInMinutes      240 -> 360  (the platform hard ceiling)
  - per-category-loop STEP timeout 220 -> 320
  - $budgetMin  (stop starting new) 185 -> 270
  - $hardStopMin (whole-loop stop)  210 -> 300
  - $perCatCapMin (single-cat cap)  150 -> 290  (~4.8 h for a lone category)
  - $perCatIdleMin (hang-killer)     25 ->  25  (unchanged)

Effect on the per-category fair-share math
(min(perCatCap, max(min(50, remain), floor(remain / catsRemaining)))):
  1 category  -> 290 min (~4.8 h)
  2 categories-> 150 min each   (was ~105 — the #36243 case)
  3 categories-> 100 min each
  6/12 cats   ->  50 min floor each

The hierarchy stays safe: loop hard stop 300 < step 320 < job 360, and the
non-loop headroom (pre-loop workload install / PR-merge + post-loop publish)
actually GROWS from 30 to 60 min, so partial results always flush before any
hard cancel. The 25-min idle no-progress tree-kill is deliberately left
unchanged: a genuinely hung build/run is still killed within 25 min of
silence, so the larger wall-clock ceiling only ever benefits a category that
is actively producing test output — it can never let a hang waste hours.

Note: Android/Windows use Microsoft-hosted agents and cannot exceed 360 min;
only the self-hosted iOS/Mac (AcesShared) pools could ever go higher, which
would require templating the job timeout per-platform.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 15d2af20-e4ab-4e88-9011-cfbd83513bc0
… and non-Loop Replace dispatched callbacks to prevent a crash during a teardown race.
Copilot AI review requested due to automatic review settings July 16, 2026 10:48
@BagavathiPerumal

Copy link
Copy Markdown
Contributor Author

AI Review Summary

@BagavathiPerumal — new AI review results are available based on this last commit: 2ea358c. 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)
🖥️ Issue35643 Issue35643 ✅ FAIL — 2522s ✅ PASS — 586s
🔴 Without fix — 🖥️ Issue35643: FAIL ✅ · 2522s
Error-relevant lines (filtered from the build log):

/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010: Mono.AndroidTools.InstallFailedException: Unexpected install output: cmd: Failure calling service package: Broken pipe (32) [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010:  [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010:    at Mono.AndroidTools.Internal.AdbOutputParsing.CheckInstallSuccess(String output, String packageName) [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010:    at Mono.AndroidTools.AndroidDevice.<>c__DisplayClass105_0.<InstallPackage>b__0(Task`1 t) [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010:    at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state) [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010: --- End of stack trace from previous location --- [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010:    at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot, Thread threadPoolThread) [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010:    at AndroidDeviceExtensions.PushAndInstallPackageAsync(AndroidDevice device, PushAndInstallCommand command, CancellationToken token) [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010:    at Xamarin.Android.Tasks.FastDeploy.InstallPackage(Boolean installed) [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010:    at Xamarin.Android.Tasks.FastDeploy.RunInstall() [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
Build FAILED.
     at Microsoft.Maui.TestCases.Tests.Issues.Issue35643.CurrentItemShouldUpdateWhenCurrentItemIsReplaced() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue35643.cs:line 31
     at Microsoft.Maui.TestCases.Tests.Issues.Issue35643.CurrentItemShouldUpdateWhenCurrentItemIsReplacedInLoopMode() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue35643.cs:line 56

🟢 With fix — 🖥️ Issue35643: PASS ✅ · 586s
(no coded error found; showing last 1200 chars)

Tests.dll
   NUnit3TestExecutor discovered 2 of 2 NUnit test cases using Current Discovery mode, Non-Explicit run
>>>>> 07/15/2026 16:25:39 FixtureSetup for Issue35643(Android)
>>>>> 07/15/2026 16:25:42 CurrentItemShouldUpdateWhenCurrentItemIsReplaced Start
>>>>> 07/15/2026 16:25:48 CurrentItemShouldUpdateWhenCurrentItemIsReplaced Stop
  Passed CurrentItemShouldUpdateWhenCurrentItemIsReplaced [6 s]
>>>>> 07/15/2026 16:25:49 CurrentItemShouldUpdateWhenCurrentItemIsReplacedInLoopMode Start
>>>>> 07/15/2026 16:25:53 CurrentItemShouldUpdateWhenCurrentItemIsReplacedInLoopMode Stop
  Passed CurrentItemShouldUpdateWhenCurrentItemIsReplacedInLoopMode [4 s]
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.50]   Discovered:  Controls.TestCases.Android.Tests
Results File: /home/vsts/work/1/s/CustomAgentLogsTmp/UITests/TestResults/Issue35643.trx

Test Run Successful.
Total tests: 2
     Passed: 2
 Total time: 25.4401 Seconds
>>> TRX_RESULT_FILE: /home/vsts/work/1/s/CustomAgentLogsTmp/UITests/TestResults/Issue35643.trx

📁 Fix files reverted (1 files)

  • src/Controls/src/Core/Handlers/Items/Android/MauiCarouselRecyclerView.cs

📱 UI Tests — CarouselView,CollectionView

Detected UI test categories: CarouselView,CollectionView

⚠️ Deep UI tests — The deep UI run for 2 categories (CarouselView, CollectionView) was interrupted before producing results — most often the per-category time budget (a very long-running category) was exhausted, or an emulator/Appium hang. This is usually an infrastructure/timeout issue rather than a code problem; re-run the review to try again. See the build-output.log in the drop-deep-uitests artifact.

📋 Pre-Flight — Context & Validation

Issue: #35643 - CurrentItem is updated incorrectly on Android when the CarouselView is bound to an ObservableCollection with Loop = false PR: #36243 - [Android] Fix for CurrentItem is updated incorrectly when the CarouselView is bound to an ObservableCollection with Loop = false Platforms Affected: Android Files Changed: 1 implementation, 2 test

Key Findings

Code Review Summary

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

Key code review findings:

  • src/Controls/src/Core/Handlers/Items/Android/MauiCarouselRecyclerView.cs:568 and :606 — dispatched Replace callbacks can run after handler teardown and dereference Carousel through SetCurrentItem, UpdatePosition, or UpdateVisualStates without revalidating lifecycle state.
  • src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue35643.cs — tests cover the main equal-count single-item Replace path, but not adjacent unequal-count, indexless Replace, or teardown/disconnect safety branches.

Fix Candidates

Source Approach Test Result Files Changed Notes

PR PR #36243 Dedicated Android equal-count Replace handler preserving position/current item, plus loop-mode visible virtual-cell rebind without adapter rebuild ✅ PASSED (Gate) src/Controls/src/Core/Handlers/Items/Android/MauiCarouselRecyclerView.cs, src/Controls/tests/TestCases.HostApp/Issues/Issue35643.cs, src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue35643.cs Original PR; gate result supplied by caller
🔬 Code Review — Deep Analysis

Code Review — PR #36243

Independent Assessment

What this changes: Adds Android CarouselView handling for equal-count NotifyCollectionChangedAction.Replace, preserving Position/CurrentItem and rebinding visible loop-mode virtual cells without a full adapter rebuild. Adds Android UI coverage for loop and non-loop replacement.

Inferred motivation: Replacing the selected item currently looks like removal because the old CurrentItem no longer exists, causing position/current item reset behavior.

Reconciliation with PR Narrative

Author claims: Android-only fix for issue #35643; preserves replace position/current item, with special loop-mode virtual-cell refresh. Agreement/disagreement: The intent matches the code. However, the new dispatched callbacks still have handler teardown races despite the PR’s lifecycle guard.

Prior Review Reconciliation

No prior ❌ Error findings found.

Notable prior [major]/[moderate] findings were mostly addressed:

  • Missing loop-mode test: ✅ fixed.
  • Range replace rebind: ✅ fixed.
  • Unequal replace clamp: ✅ fixed.
  • Indexless replace: ✅ mostly addressed.
  • Latest UI-thread adapter-notification comments: likely obsolete because ObservableItemsSource.CollectionChanged dispatches via _container.Dispatcher.DispatchIfRequired(...) before raising CollectionItemsSourceChanged.

Blast Radius Assessment

  • Runs for all instances: No; only Android CarouselView collection changes.
  • Startup impact: No.
  • Static/shared state: No.
  • Handler/platform plumbing: Yes — confidence capped at medium, then CI red caps to low.

CI Status

  • Required-check result: gh pr checks --required unavailable due unauthenticated gh; fallback GitHub Checks API shows maui-pr failed.
  • Classification: CI failure appears PR-unrelated infra. AzDO build 1510132 failed in RunOniOS_BlazorDebug ARM64 because Install Simulator Runtimes timed out while downloading iOS 26.0 simulator; unrelated to Android CarouselView code.
  • Action taken: Invoked azdo-build-investigator; confidence capped low because CI is red/tool fallback was required.

Findings

❌ Error — Deferred Replace callbacks can still run after handler teardown

CollectionItemsSourceChanged guards Carousel?.Handler?.MauiContext before entering HandleReplaceAction, but both new dispatcher callbacks dereference Carousel later without revalidating lifecycle state.

Affected lines:

  • src/Controls/src/Core/Handlers/Items/Android/MauiCarouselRecyclerView.cs:568
  • src/Controls/src/Core/Handlers/Items/Android/MauiCarouselRecyclerView.cs:606

If TearDownOldElement/handler disconnect happens after Dispatch(...) queues but before the callback executes, ItemsView/Carousel can be null. Then SetCurrentItem, UpdatePosition, or UpdateVisualStates can throw. Re-check Carousel?.Handler?.MauiContext inside each dispatched lambda before touching carousel state, while still resetting _isInternalPositionUpdate/_noNeedForScroll in finally.

⚠️ Warning — Adjacent Replace edge cases remain untested

The tests cover the main equal-count single-item replace path, including loop mode visible-cell rebind. They do not cover adjacent branches added by this PR: unequal-count replace clamping, indexless replace fallback, or teardown/disconnect safety. Given the handler complexity, at least one lighter adjacent test would reduce regression risk.

Failure-Mode Probing

  • Handler disconnect after dispatch: currently unsafe; callback can dereference Carousel after teardown.
  • Dispatch refuses to queue: flags are reset; handled.
  • Empty collection after unequal replace: clamped to 0; avoids ScrollToPosition(-1).
  • Multi-item equal replace in loop mode: iterates replaced range; addressed.
  • Background collection change: ObservableItemsSource marshals via dispatcher before raising this handler event.

Verdict: NEEDS_CHANGES

Confidence: low Summary: The fix addresses the reported behavior and prior review concerns, but the new deferred callbacks still have a concrete Android handler lifecycle race. CI is also currently red, though the observed failure appears infrastructure-related rather than PR-caused.

🛠️ Fix — Analysis & Comparison

Fix Candidates

Source Approach Test Result Files Changed Notes

1 try-fix-1 / maui-expert-reviewer Synchronous count-preserving Replace reconciliation; no deferred dispatch; NotifyDataSetChanged() only for loop-mode virtual cell refresh ✅ PASS 1 file Simpler than PR fix and eliminates the lifecycle race found in pre-flight review
PR PR #36243 Dedicated equal-count Replace handler with deferred callbacks and targeted visible loop virtual-cell rebind ✅ PASSED (Gate) 3 files Original PR; gate result supplied by caller

Cross-Pollination

Model Round New Ideas? Details
maui-expert-reviewer 1 Yes Proposed synchronous count-preserving Replace reconciliation as a different root-cause/implementation approach
Exhausted: No — stopped after Candidate #1 because it passed the Android regression tests and is demonstrably simpler while removing the PR fix's deferred-callback lifecycle race. Selected Fix: Candidate #1 — passes the same target tests, changes only the Android implementation file, removes the queued dispatch teardown hazard, and has a substantially smaller implementation. Tradeoff: loop-mode refresh is coarser than the PR's targeted virtual-cell notification.

Environment notes: gh is unauthenticated in this environment, so GitHub CLI PR queries were replaced with public GitHub API reads. EstablishBrokenBaseline.ps1 could not establish a broken baseline because the repository already contained unrelated dirty .github/eng files; the attempt continued by changing only src/Controls/src/Core/Handlers/Items/Android/MauiCarouselRecyclerView.cs and capturing the diff separately.

📝 Recommended PR Title & Description

Assessment: ✏️ Recommend updating — the current description is strong, but the winning fix adds deferred-callback lifecycle revalidation that is not reflected, and the title can be made shorter and more component-focused.

Recommended title

[Android] CarouselView: Preserve CurrentItem when replacing the selected item

Recommended description

### Issue details

The issue occurs on Android when replacing an item in the CarouselView.ItemsSource while Loop is set to false and simultaneously updating the CurrentItem. If the replaced item is the currently selected item, CarouselView incorrectly resets the selection to the first item instead of preserving the updated item as the current selection.

### Root Cause

When ItemsUpdatingScrollMode support was added to CarouselView collection change handling on Android, the change correctly implemented scroll-mode logic for Add, Remove, and Reset actions but did not add a dedicated path for the Replace action. This caused Replace to fall through into the KeepItemsInView/KeepLastItemInView scroll logic.

GetPosition(CurrentItem) always returns -1 after a Replace (old item gone from source), making removingCurrentElement = true and triggering a position reset to 0.

### Description of Change

The fix involves intercepting the Replace action at the top of CollectionItemsSourceChanged — before any Remove/Insert flags are computed — and delegating to a dedicated HandleReplaceAction method, ensuring Replace never reaches the KeepItemsInView reset logic.

For non-loop mode, SetCurrentItem and UpdatePosition are dispatched at the preserved position with no scroll. For loop mode, a new RebindVisibleLoopItem helper surgically rebinds only the visible virtual cells that map to the replaced real index, avoiding a full adapter rebuild that previously caused a flash to position 0 and spurious events. The deferred Replace callbacks also re-check Carousel.Handler.MauiContext before applying state updates so handler teardown between dispatch and callback execution does not dereference a disconnected CarouselView. All existing Remove, Reset, and Insert behavior is fully preserved.

The Android UI tests cover both Loop=false and Loop=true replacement. The loop-mode test verifies the visible carousel cell is rebound to the replacement item and scrolls the LoopCarouselView back into view before querying the cell AutomationId so RecyclerView does not recycle the target cell off-screen.

### Regression PR

PR https://github.com/dotnet/maui/pull/26608

Tested the behavior in the following platforms.

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

### Issues Fixed

Fixes https://github.com/dotnet/maui/issues/35643

### Output

|Platform|Before|After|
|--|--|--|
|Android|<video src="https://github.com/user-attachments/assets/093a0324-9102-400f-944e-56a11565acc4"> |<video src="https://github.com/user-attachments/assets/08ebeb5c-59c3-4640-af15-530053c0cebb">|

🏁 Report — Final Recommendation

Comparative Report — PR #36243

Candidates compared

Rank Candidate Regression result Assessment
1 pr-plus-reviewer Not separately re-run; preserves the raw PR's passing regression path and only adds lifecycle guards inside the new Replace callbacks plus a test scroll-back before asserting the visible loop cell Best overall. Keeps the PR's comprehensive equal-count Replace handling, loop-mode targeted visible-cell rebind, and Android UI tests, while fixing the actionable deferred-dispatch teardown race and small-screen test reliability issue.
2 try-fix-1 ✅ PASS Strong alternative. Simpler synchronous count-preserving Replace reconciliation removes the deferred callback race entirely and passed the Issue35643 Android UI tests. Ranked below pr-plus-reviewer because it is coarser for loop mode (NotifyDataSetChanged) and only handles equal-count Replace when the current position is inside the replaced range, whereas the PR path consistently short-circuits equal-count Replace and preserves current carousel state.
3 pr ✅ PASSED gate Functionally addresses the reported regression and includes good UI coverage, but remains below the other passing candidates because expert review identified an actionable lifecycle race in the newly queued Replace callbacks and a loop-mode test reliability issue after scrolling to the button.
No candidate failed the supplied regression gate. Per the ranking rule, a regression-failing candidate would be ranked below all passing candidates; that condition did not apply here.

Winning candidate

pr-plus-reviewer

Rationale

The raw PR fix correctly identifies the root cause: Android equal-count Replace was falling through into removal / scroll-mode logic because the old CurrentItem no longer exists in the source. pr-plus-reviewer preserves that fix and the PR's loop-mode virtual-cell rebind strategy, while applying the expert reviewer's concrete lifecycle feedback by re-checking Carousel?.Handler?.MauiContext inside each deferred Replace callback before touching carousel state. It also applies the reviewer test feedback by scrolling LoopCarouselView back into view before asserting the visible rebound cell.

Compared with try-fix-1, pr-plus-reviewer has slightly more implementation complexity, but it retains the PR's more precise loop-mode updates and broader equal-count Replace handling. The added reviewer changes are surgical and do not alter the successful regression behavior except in unsafe/disconnected handler states or when stabilizing the UI test's visibility precondition.

🧭 Next Steps — review latest findings

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

I've reviewed all the outstanding concerns from the AI review and addressed them as follows:

  • Null safety (Loop & non-Loop Replace callbacks) — Added a Carousel is null check inside both dispatched callbacks. Since these callbacks run asynchronously, the view could be torn down before they execute, which could cause a crash. This is now handled safely.

  • Thread safety for adapter refresh calls — Verified that these code paths always run on the UI thread already, since the triggering event is dispatched to the UI thread beforehand. No changes were needed here.

  • Test scroll behavior — Verified that the loop carousel cell remains visible after scrolling to the button, so the existing test passes reliably without additional changes.

Copilot AI 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.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

@kubaflo

kubaflo commented Jul 16, 2026

Copy link
Copy Markdown
Collaborator

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 3 pipeline(s).

@kubaflo

This comment has been minimized.

@github-actions

Copy link
Copy Markdown
Contributor

Tests Failure Analysis

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

Overall Not ready Failures 11 Regressed vs base 2 Baseline 2 on base

Test Failure Review: Not ready - click to expand

Overall verdict: Not ready. Of 11 distinct failures, 2 legs are deterministic regressions vs the base branch (main, sampled across 5 recent base builds for maui-pr-uitests): a real test NRE and a transient artifact-upload break. The 2 failures that also appear on base (platform-tools;35.0.2 provisioning) are flaky-on-base and not dismissable, and 13 build legs plus 2 cancelled macOS checks produced no extractable evidence — a human must inspect them.

Coverage: 162 checks · 155 passing · 7 failing · 0 pending · 0 inaccessible · 1 unmapped · 13 unexplained build legs · 0 unaccounted failing checks · 2 aborted failing checks · 0 canceled-build checks · 0 device-test unverified · 9 unattributed · 2 regressed-vs-base. Deterministic ceiling: Not ready — 2 legs regressed vs base plus unexplained/aborted legs and unattributed failures.

Builds (this PR): maui-pr-uitests 1512303, maui-pr-devicetests 1512304. Base sampling (main, 5 recent builds per definition): 1503618, 1503332, 1503036.

Recommended action

Have a human inspect the DatePickerOpenedAndClosedEventsAreRaised NRE regression and the 13 unexplained + 2 cancelled macOS legs before merging; the remaining provisioning/flaky failures should be re-run to confirm they clear.

@BagavathiPerumal

Copy link
Copy Markdown
Contributor Author

Tests Failure Analysis

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

Overall Not ready Failures 11 Regressed vs base 2 Baseline 2 on base

Test Failure Review: Not ready - click to expand

I have reviewed the reported failures and confirmed that they are unrelated to this fix.

@kubaflo
kubaflo changed the base branch from main to inflight/current July 17, 2026 14:02
@kubaflo
kubaflo merged commit 1e46a3b into dotnet:inflight/current Jul 17, 2026
154 of 169 checks passed
@github-actions github-actions Bot added this to the .NET 10 SR10 milestone Jul 17, 2026
kubaflo pushed a commit that referenced this pull request Jul 22, 2026
…lView is bound to an ObservableCollection with Loop = false (#36243)

> [!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 issue occurs on Android when replacing an item in the
CarouselView.ItemsSource while Loop is set to false and simultaneously
updating the CurrentItem. If the replaced item is the currently selected
item, CarouselView incorrectly resets the selection to the first item
instead of preserving the updated item as the current selection.

### Root Cause

When ItemsUpdatingScrollMode support was added to CarouselView
collection change handling on Android, the change correctly implemented
scroll-mode logic for Add, Remove, and Reset actions but did not add a
dedicated path for the Replace action. This caused Replace to fall
through into the KeepItemsInView/KeepLastItemInView scroll logic.

GetPosition(CurrentItem) always returns -1 after a Replace (old item
gone from source), making removingCurrentElement = true and triggering a
position reset to 0.

### Description of Change

The fix involves intercepting the Replace action at the top of
CollectionItemsSourceChanged — before any Remove/Insert flags are
computed — and delegating to a dedicated HandleReplaceAction method,
ensuring Replace never reaches the KeepItemsInView reset logic.

For non-loop mode, SetCurrentItem and UpdatePosition are dispatched at
the preserved position with no scroll. For loop mode, a new
RebindVisibleLoopItem helper surgically rebinds only the visible virtual
cells that map to the replaced real index, avoiding a full adapter
rebuild that previously caused a flash to position 0 and spurious
events. All existing Remove, Reset, and Insert behavior is fully
preserved.

### Regression PR

PR #26608

Tested the behavior in the following platforms.
 
- [x] Android
- [ ] Mac
- [ ] iOS
- [ ] Windows

### Issues Fixed

Fixes #35643

### Output

|Platform|Before|After|
|--|--|--|
|Android|<video
src="https://github.com/user-attachments/assets/093a0324-9102-400f-944e-56a11565acc4">
|<video
src="https://github.com/user-attachments/assets/08ebeb5c-59c3-4640-af15-530053c0cebb">|
kubaflo pushed a commit that referenced this pull request Jul 28, 2026
…lView is bound to an ObservableCollection with Loop = false (#36243)

> [!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 issue occurs on Android when replacing an item in the
CarouselView.ItemsSource while Loop is set to false and simultaneously
updating the CurrentItem. If the replaced item is the currently selected
item, CarouselView incorrectly resets the selection to the first item
instead of preserving the updated item as the current selection.

### Root Cause

When ItemsUpdatingScrollMode support was added to CarouselView
collection change handling on Android, the change correctly implemented
scroll-mode logic for Add, Remove, and Reset actions but did not add a
dedicated path for the Replace action. This caused Replace to fall
through into the KeepItemsInView/KeepLastItemInView scroll logic.

GetPosition(CurrentItem) always returns -1 after a Replace (old item
gone from source), making removingCurrentElement = true and triggering a
position reset to 0.

### Description of Change

The fix involves intercepting the Replace action at the top of
CollectionItemsSourceChanged — before any Remove/Insert flags are
computed — and delegating to a dedicated HandleReplaceAction method,
ensuring Replace never reaches the KeepItemsInView reset logic.

For non-loop mode, SetCurrentItem and UpdatePosition are dispatched at
the preserved position with no scroll. For loop mode, a new
RebindVisibleLoopItem helper surgically rebinds only the visible virtual
cells that map to the replaced real index, avoiding a full adapter
rebuild that previously caused a flash to position 0 and spurious
events. All existing Remove, Reset, and Insert behavior is fully
preserved.

### Regression PR

PR #26608

Tested the behavior in the following platforms.
 
- [x] Android
- [ ] Mac
- [ ] iOS
- [ ] Windows

### Issues Fixed

Fixes #35643

### Output

|Platform|Before|After|
|--|--|--|
|Android|<video
src="https://github.com/user-attachments/assets/093a0324-9102-400f-944e-56a11565acc4">
|<video
src="https://github.com/user-attachments/assets/08ebeb5c-59c3-4640-af15-530053c0cebb">|
kubaflo pushed a commit that referenced this pull request Jul 29, 2026
…lView is bound to an ObservableCollection with Loop = false (#36243)

> [!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 issue occurs on Android when replacing an item in the
CarouselView.ItemsSource while Loop is set to false and simultaneously
updating the CurrentItem. If the replaced item is the currently selected
item, CarouselView incorrectly resets the selection to the first item
instead of preserving the updated item as the current selection.

### Root Cause

When ItemsUpdatingScrollMode support was added to CarouselView
collection change handling on Android, the change correctly implemented
scroll-mode logic for Add, Remove, and Reset actions but did not add a
dedicated path for the Replace action. This caused Replace to fall
through into the KeepItemsInView/KeepLastItemInView scroll logic.

GetPosition(CurrentItem) always returns -1 after a Replace (old item
gone from source), making removingCurrentElement = true and triggering a
position reset to 0.

### Description of Change

The fix involves intercepting the Replace action at the top of
CollectionItemsSourceChanged — before any Remove/Insert flags are
computed — and delegating to a dedicated HandleReplaceAction method,
ensuring Replace never reaches the KeepItemsInView reset logic.

For non-loop mode, SetCurrentItem and UpdatePosition are dispatched at
the preserved position with no scroll. For loop mode, a new
RebindVisibleLoopItem helper surgically rebinds only the visible virtual
cells that map to the replaced real index, avoiding a full adapter
rebuild that previously caused a flash to position 0 and spurious
events. All existing Remove, Reset, and Insert behavior is fully
preserved.

### Regression PR

PR #26608

Tested the behavior in the following platforms.
 
- [x] Android
- [ ] Mac
- [ ] iOS
- [ ] Windows

### Issues Fixed

Fixes #35643

### Output

|Platform|Before|After|
|--|--|--|
|Android|<video
src="https://github.com/user-attachments/assets/093a0324-9102-400f-944e-56a11565acc4">
|<video
src="https://github.com/user-attachments/assets/08ebeb5c-59c3-4640-af15-530053c0cebb">|
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-controls-collectionview CollectionView, CarouselView, IndicatorView community ✨ Community Contribution partner/syncfusion Issues / PR's with Syncfusion collaboration platform/android 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.

CurrentItem is updated incorrectly on Android when the CarouselView is bound to an ObservableCollection with Loop = false

5 participants