Skip to content

[Android] CarouselView: Fix scroll to last item after data reset in loop mode - #31672

Merged
kubaflo merged 9 commits into
dotnet:inflight/currentfrom
SyedAbdulAzeemSF4852:fix-23023
Jul 5, 2026
Merged

kubaflo merged 9 commits into
dotnet:inflight/currentfrom
SyedAbdulAzeemSF4852:fix-23023

Conversation

@SyedAbdulAzeemSF4852

@SyedAbdulAzeemSF4852 SyedAbdulAzeemSF4852 commented Sep 18, 2025 •

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 :

  • When the item source is reloaded and items are added dynamically, updating the CurrentItem to one of the last items correctly changes the property, but the carousel fails to visually scroll to that position.

Root Cause:

  • When ScrollToPosition(carouselPosition) was called with a logical position like 0 (i.e., the CarouselView position), it scrolled to the raw adapter position 0. However, position 0 in the virtualized array represented the beginning of the full range, which was not the correct location for proper looping behavior. As a result, the center position was set to 0. Then, when attempting to scroll backward, the logic subtracted the target item index from this center position (0), leading to negative values.
  • This caused the scroll operation to fail, and no scrolling took place.

Description of Change

  • Updated GetGoToIndex in CarouselViewLoopManager.cs to correctly handle empty item sources and fix the calculation for determining the shortest scroll path in loop mode.
  • Added a new helper method UpdateLoopCentering to MauiCarouselRecyclerView.cs that recalculates and centers the carousel on the correct item when in loop mode, both after collection changes and during initial position updates. This ensures the view is properly centered even after resetting the data or changing the selected item.

Issues Fixed

Fixes #23023

Validated the behaviour in the following platforms

  • Windows - Test fails on Windows — tracked in #31670
  • Android
  • iOS
  • Mac

Output

Before After
Before.mov
After.mov

@dotnet-policy-service dotnet-policy-service Bot added community ✨ Community Contribution partner/syncfusion Issues / PR's with Syncfusion collaboration labels Sep 18, 2025
@jsuarezruiz jsuarezruiz added platform/android area-controls-collectionview CollectionView, CarouselView, IndicatorView labels Sep 18, 2025
@jsuarezruiz

Copy link
Copy Markdown
Contributor

/azp run

@azure-pipelines

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

@SyedAbdulAzeemSF4852
SyedAbdulAzeemSF4852 marked this pull request as ready for review October 17, 2025 04:53
Copilot AI review requested due to automatic review settings October 17, 2025 04:53

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

Fixes incorrect centering/scrolling behavior of CarouselView (loop mode) on Android after the ItemsSource is reset and CurrentItem points to a tail item.
Key changes:

  • Adjusted loop index calculation in GetGoToIndex to use modular arithmetic and added bounds/empty checks.
  • Added UpdateLoopCentering helper and invoked it after collection changes and during initial position setup when looping.
  • Added a new UI test (Issue23023) and corresponding host page to reproduce and validate the scenario.

Reviewed Changes

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

File Description
src/Controls/src/Core/Handlers/Items/Android/CarouselViewLoopManager.cs Corrects loop navigation index calculations and adds input validation.
src/Controls/src/Core/Handlers/Items/Android/MauiCarouselRecyclerView.cs Introduces UpdateLoopCentering to properly center after resets and refactors initial positioning logic.
src/Controls/tests/TestCases.HostApp/Issues/Issue23023.cs Adds a repro page with looping CarouselView and controls to reload items and scroll to last item.
src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue23023.cs Adds UI test exercising reload + scroll-to-last-item scenario (currently wrapped in a conditional compilation symbol).

@jsuarezruiz

Copy link
Copy Markdown
Contributor

/azp run

@azure-pipelines

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

@github-actions

github-actions Bot commented Dec 9, 2025 •

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 -- 31672

Or

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

@rmarinho rmarinho added s/agent-review-incomplete 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) labels Feb 18, 2026
@SyedAbdulAzeemSF4852 SyedAbdulAzeemSF4852 changed the title [Android] Fix for CarouselView not scrolling to the last item after data reset despite CurrentItem being updated [Android] CarouselView: Fix scroll to last item after data reset in loop mode Feb 26, 2026
@SyedAbdulAzeemSF4852

Copy link
Copy Markdown
Contributor Author

Addressed concerns raised in the AI summary.

@dotnet dotnet deleted a comment from rmarinho Mar 15, 2026
@kubaflo kubaflo added s/agent-approved AI agent recommends approval - PR fix is correct and optimal s/agent-fix-pr-picked AI could not beat the PR fix - PR is the best among all candidates and removed s/agent-review-incomplete s/agent-approved AI agent recommends approval - PR fix is correct and optimal s/agent-gate-passed AI verified tests catch the bug (fail without fix, pass with fix) labels Mar 15, 2026
@MauiBot MauiBot added the s/agent-changes-requested AI agent recommends changes - found a better alternative or issues label Mar 29, 2026

@kubaflo kubaflo left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The test failed

@SyedAbdulAzeemSF4852

Copy link
Copy Markdown
Contributor Author

The test failed

@kubaflo , I checked the test locally — it passes with the fix and fails without it. I’ve added the test output below for your reference.

With_Fix Without_Fix

@kubaflo

kubaflo commented Mar 31, 2026

Copy link
Copy Markdown
Contributor

/azp run maui-pr-uitests

@azure-pipelines

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

@azure-pipelines

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

Copilot AI review requested due to automatic review settings June 30, 2026 09:57

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 4 out of 7 changed files in this pull request and generated 1 comment.

Comment on lines +386 to +389
if (Carousel.Loop)
{
UpdateLoopCentering(itemCount);
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This concern is not valid — the early return on the first call is self-healed by a second UpdateAdapter() triggered as a side effect of SetCurrentItem(), which exists in both old and new code paths, so there is no regression.

@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 — 1 findings

See inline comments for details.

ScrollHelper.JumpScrollToPosition(index, Microsoft.Maui.Controls.ScrollToPosition.Center);
if (Carousel.Loop)
{
UpdateLoopCentering(itemCount);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

🔍 AI-Generated Review (multi-model)

[major] CollectionView Android — UpdateInitialPosition still calls UpdateLoopCentering with itemCount == 0 when Carousel.Loop is true, CurrentItem is null, and the initial Carousel.Position is > 0. In that scenario SetCurrentItem(_oldPosition) updates CurrentItem, but UpdateLoopCentering returns without scrolling, so the looped carousel can report the requested item while visually remaining uncentered. Source the loop item count from ItemsViewAdapter.ItemsSource.Count for all looped initial positions before centering.

@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

@SyedAbdulAzeemSF4852 — new AI review results are available based on this last commit: b77d26a. 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)
🖥️ Issue23023 Issue23023 ✅ FAIL — 2332s ✅ PASS — 563s
🔴 Without fix — 🖥️ Issue23023: FAIL ✅ · 2332s

(truncated to last 15,000 chars)

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.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:    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: --- 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 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 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.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]
    0 Warning(s)
    1 Error(s)

Time Elapsed 00:16:05.48
* daemon not running; starting now at tcp:5037
* daemon started successfully
  Determining projects to restore...
  All projects are up-to-date for restore.
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529298
  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.14529298
  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.14529298
  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.14529298
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529298
  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.14529298
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529298
  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
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529298
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529298
  Controls.Xaml -> /home/vsts/work/1/s/artifacts/bin/Controls.Xaml/Debug/net10.0-android36.0/Microsoft.Maui.Controls.Xaml.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.14529298
  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.14529298
  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.14529298
  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.14529298
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529298
  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.14529298
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529298
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529298
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529298
  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
  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

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

Time Elapsed 00:08:40.03
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.68 sec).
  Restored /home/vsts/work/1/s/src/TestUtils/src/VisualTestUtils.MagickNet/VisualTestUtils.MagickNet.csproj (in 7.39 sec).
  Restored /home/vsts/work/1/s/src/Controls/tests/TestCases.Android.Tests/Controls.TestCases.Android.Tests.csproj (in 9.18 sec).
  Restored /home/vsts/work/1/s/src/TestUtils/src/UITest.Core/UITest.Core.csproj (in 6 ms).
  Restored /home/vsts/work/1/s/src/TestUtils/src/UITest.Appium/UITest.Appium.csproj (in 2 ms).
  Restored /home/vsts/work/1/s/src/TestUtils/src/UITest.NUnit/UITest.NUnit.csproj (in 626 ms).
  Restored /home/vsts/work/1/s/src/Controls/tests/CustomAttributes/Controls.CustomAttributes.csproj (in 4 ms).
  Restored /home/vsts/work/1/s/src/TestUtils/src/UITest.Analyzers/UITest.Analyzers.csproj (in 3.22 sec).
  5 of 13 projects are up-to-date for restore.
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529298
  Graphics -> /home/vsts/work/1/s/artifacts/bin/Graphics/Debug/net10.0/Microsoft.Maui.Graphics.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529298
  Controls.CustomAttributes -> /home/vsts/work/1/s/artifacts/bin/Controls.CustomAttributes/Debug/net10.0/Controls.CustomAttributes.dll
  Essentials -> /home/vsts/work/1/s/artifacts/bin/Essentials/Debug/net10.0/Microsoft.Maui.Essentials.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529298
  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.14529298
  Controls.Core -> /home/vsts/work/1/s/artifacts/bin/Controls.Core/Debug/net10.0/Microsoft.Maui.Controls.dll
  UITest.Core -> /home/vsts/work/1/s/artifacts/bin/UITest.Core/Debug/net10.0/UITest.Core.dll
  VisualTestUtils -> /home/vsts/work/1/s/artifacts/bin/VisualTestUtils/Debug/netstandard2.0/VisualTestUtils.dll
  UITest.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.Appium -> /home/vsts/work/1/s/artifacts/bin/UITest.Appium/Debug/net10.0/UITest.Appium.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:55:41 FixtureSetup for Issue23023(Android)
>>>>> 06/30/2026 14:55:45 VerifyCarouselScrollsToEndItemAfterReset Start
>>>>> 06/30/2026 14:55:53 VerifyCarouselScrollsToEndItemAfterReset Stop
>>>>> 06/30/2026 14:55:53 Log types: logcat, bugreport, server
  Failed VerifyCarouselScrollsToEndItemAfterReset [8 s]
  Error Message:
   VisualTestUtils.VisualTestFailedException : 
Snapshot different than baseline: VerifyCarouselScrollsToEndItemAfterReset.png (1.88% 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

  Stack Trace:
     at VisualTestUtils.VisualRegressionTester.Fail(String message) in /_/src/TestUtils/src/VisualTestUtils/VisualRegressionTester.cs:line 162
   at VisualTestUtils.VisualRegressionTester.VerifyMatchesSnapshot(String name, ImageSnapshot actualImage, String environmentName, ITestContext testContext) in /_/src/TestUtils/src/VisualTestUtils/VisualRegressionTester.cs:line 123
   at Microsoft.Maui.TestCases.Tests.UITest.<VerifyScreenshot>g__Verify|13_0(String name, <>c__DisplayClass13_0&) in /_/src/Controls/tests/TestCases.Shared.Tests/UITest.cs:line 477
   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 309
   at Microsoft.Maui.TestCases.Tests.Issues.Issue23023.VerifyCarouselScrollsToEndItemAfterReset() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue23023.cs:line 32
   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.14]   Discovering: Controls.TestCases.Android.Tests
[xUnit.net 00:00:00.57]   Discovered:  Controls.TestCases.Android.Tests
Results File: /home/vsts/work/1/s/CustomAgentLogsTmp/UITests/TestResults/Issue23023.trx

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

🟢 With fix — 🖥️ Issue23023: PASS ✅ · 563s
  Determining projects to restore...
  All projects are up-to-date for restore.
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529298
  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.14529298
  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.14529298
  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.14529298
  Maps -> /home/vsts/work/1/s/artifacts/bin/Maps/Debug/net10.0-android36.0/Microsoft.Maui.Maps.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529298
  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.14529298
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529298
  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
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529298
  Controls.Xaml -> /home/vsts/work/1/s/artifacts/bin/Controls.Xaml/Debug/net10.0-android36.0/Microsoft.Maui.Controls.Xaml.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529298
  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.14529298
  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.14529298
  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.14529298
  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.14529298
  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.14529298
  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.14529298
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529298
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529298
  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.14529298
  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:07:19.02
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.
  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.14529298
  Graphics -> /home/vsts/work/1/s/artifacts/bin/Graphics/Debug/net10.0/Microsoft.Maui.Graphics.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529298
  Essentials -> /home/vsts/work/1/s/artifacts/bin/Essentials/Debug/net10.0/Microsoft.Maui.Essentials.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14529298
  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.14529298
  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 15:15:08 FixtureSetup for Issue23023(Android)
>>>>> 06/30/2026 15:15:11 VerifyCarouselScrollsToEndItemAfterReset Start
>>>>> 06/30/2026 15:15:17 VerifyCarouselScrollsToEndItemAfterReset Stop
  Passed VerifyCarouselScrollsToEndItemAfterReset [6 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.63]   Discovered:  Controls.TestCases.Android.Tests
Results File: /home/vsts/work/1/s/CustomAgentLogsTmp/UITests/TestResults/Issue23023.trx

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

📁 Fix files reverted (2 files)
  • src/Controls/src/Core/Handlers/Items/Android/CarouselViewLoopManager.cs
  • 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: #23023 - [Android] CarouselView many issues with CurrentItem bindings
PR: #31672 - [Android] CarouselView: Fix scroll to last item after data reset in loop mode
Platforms Affected: Android
Files Changed: 2 implementation, 5 test/snapshot

Key Findings

  • Issue #23023's critical reproduced scenario is Android CarouselView loop mode: after reloading a source with more than about six items and selecting an end item, CurrentItem changes but the visible item remains at the start.
  • PR #31672 changes Android CarouselView loop scrolling by adding nearest adapter-position calculation, refreshing loop-manager item source after adapter rebuilds, and using loop-aware centering after reset/initial positioning.
  • Prior review feedback asked for newPosition bounds validation and additional snapshots; the current PR includes bounds validation and platform snapshots.
  • UI test type is UITest; targeted Android command: pwsh .github/scripts/BuildAndRunHostApp.ps1 -Platform android -TestFilter "FullyQualifiedName~Issue23023".
  • Impacted UI test category: CarouselView.

Code Review Summary

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

Key code review findings:

  • ✗ src/Controls/src/Core/Handlers/Items/Android/MauiCarouselRecyclerView.cs:388 — looped initial Position > 0 with no CurrentItem can skip loop centering because itemCount remains 0, causing UpdateLoopCentering to return without scrolling.
  • Failure mode: Loop=true, Position=0 works; Loop=true, Position>0, CurrentItem=null sets _oldPosition/CurrentItem but does not scroll; CurrentItem-initialized looped carousel works if the item is found.
  • Blast radius: Android CarouselView loop-mode paths only, with startup/initial-position impact; no new shared static state.

Fix Candidates

# Source Approach Test Result Files Changed Notes
PR PR #31672 Recompute nearest looped adapter position and explicitly re-center looped carousel after data reset/initialization. ✅ PASSED (Gate) CarouselViewLoopManager.cs, MauiCarouselRecyclerView.cs, UITest/snapshots Original PR; gate result supplied by caller.

🔬 Code Review — Deep Analysis

Code Review — PR #31672

Independent Assessment

What this changes: Android CarouselView loop-mode scrolling is reworked to compute the nearest looped adapter position, refresh the loop manager’s source after adapter rebuilds, and re-center looped carousels after resets/initial positioning. A UI repro/test for issue 23023 is added.

Inferred motivation: Fix cases where resetting the item source and then selecting an end item updates CurrentItem/Position but leaves the Android carousel visually at the wrong loop slot.

Reconciliation with PR Narrative

Author claims: The PR fixes loop-mode scroll-to-last-item after data reset by replacing raw adapter-position scrolling with loop-aware centering and by keeping the loop manager’s item source current.

Agreement/disagreement: The reset path now avoids the earlier raw-scroll-after-centering problem, matching the claimed root cause. However, the new initial-position path introduces a real regression for looped carousels initialized with Position > 0 and no CurrentItem.

Prior Review Reconciliation

Prior ❌ Error Finding Source Status Evidence
Loop centering after reset was immediately followed by raw ScrollToPosition(carouselPosition), moving back to adapter slot 0. MauiBot [major] inline comment ✅ Fixed Current code uses if (Carousel.Loop) UpdateLoopCentering(count); else ScrollToPosition(carouselPosition); at MauiCarouselRecyclerView.cs:321-327.
UpdateInitialPosition() can skip initial loop scroll when Loop=true, CurrentItem=null, and Position>0 because itemCount remains 0. MauiBot [major] inline comment ❌ Unresolved Current code still only sets itemCount in the CurrentItem == null branch when position == 0, then calls UpdateLoopCentering(itemCount) at MauiCarouselRecyclerView.cs:375-388; UpdateLoopCentering returns on itemCount == 0 at lines 408-412.

Blast Radius Assessment

  • Runs for all instances: No — Android CarouselView loop-mode paths only.
  • Startup impact: Yes, for looped Android CarouselView initial positioning.
  • Static/shared state: No new static/shared state.

CI Status

  • Required-check result: gh pr checks --required could not run because gh is unauthenticated in this environment.
  • Supplemental check result: Public check-runs show maui-pr / Build Analysis failing on head SHA b77d26a, with Build Analysis classifying the visible failure as known infrastructure timeout in Windows Helix Unit Tests.
  • Classification: CI red; visible failure appears infra-related, but required-check status could not be authoritatively queried.
  • Action taken: Invoked azdo-build-investigator; capped confidence low.

Findings

❌ Error — Looped initial Position > 0 no longer scrolls to the requested item

src/Controls/src/Core/Handlers/Items/Android/MauiCarouselRecyclerView.cs:388

UpdateInitialPosition() now delegates looped initial scrolling to UpdateLoopCentering(itemCount), but itemCount is still 0 when Carousel.CurrentItem is null and Carousel.Position is non-zero:

position = Carousel.Position;
if (Carousel.Loop && position == 0)
{
    itemCount = ItemsViewAdapter.ItemsSource.Count;
}
...
UpdateLoopCentering(itemCount);

UpdateLoopCentering() returns immediately for itemCount == 0, so a looped Android carousel initialized like Loop="True" Position="3" with no initial CurrentItem sets _oldPosition/CurrentItem but never scrolls the RecyclerView to the requested loop-centered adapter slot. Populate itemCount from ItemsViewAdapter.ItemsSource.Count for all looped initial positions before calling UpdateLoopCentering().

Failure-Mode Probing

  • Initial looped carousel with Position=0: itemCount is populated and centering works.
  • Initial looped carousel with Position>0 and no CurrentItem: itemCount remains 0; no scroll occurs.
  • Initial looped carousel with CurrentItem set: enumeration populates itemCount; centering works if the item is found.
  • Empty item source: guarded by the existing early return.

Verdict: NEEDS_CHANGES

Confidence: low

Summary: The reset fix direction is sound, and one prior major sequencing issue has been addressed. However, a prior major Android loop initialization regression remains present in the current code, and CI is currently red/partially unverifiable from this environment.


🛠️ Fix — Analysis & Comparison

Fix Candidates

# Source Approach Test Result Files Changed Notes
1 try-fix-1 Keep existing scroll flow, sync loop-manager source after adapter rebuild, convert logical positions to looped adapter positions at scroll sites, and always source loop itemCount from the adapter during initialization. ✅ PASS 2 files Simpler than PR fix; passes Android Issue23023 UI test and addresses pre-flight Position > 0 initialization concern.
PR PR #31672 Add nearest-adapter-position helper plus UpdateLoopCentering helper for reset/initialization paths. ✅ PASSED (Gate) 2 implementation files + UITest/snapshots Original PR; gate result supplied by caller.

Cross-Pollination

Model Round New Ideas? Details
claude-opus-4.6 1 Yes Produced Candidate 1.

Exhausted: No
Selected Fix: Candidate #1 — It passed the Android regression test and is materially simpler than PR #31672's current fix. It avoids the PR's new nearest-position and centering helpers while also fixing the independent review's Loop=true, Position>0, CurrentItem=null initialization concern.

Test Evidence

Candidate #1 ran:

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

Result:

  • Build succeeded with 0 errors.
  • VerifyCarouselScrollsToEndItemAfterReset passed on Android emulator emulator-5554.
  • Test run successful: 1 total, 1 passed.

Full attempt artifacts:

  • CustomAgentLogsTmp/PRState/31672/PRAgent/try-fix/attempt-1/approach.md
  • CustomAgentLogsTmp/PRState/31672/PRAgent/try-fix/attempt-1/fix.diff
  • CustomAgentLogsTmp/PRState/31672/PRAgent/try-fix/attempt-1/test-output.log
  • CustomAgentLogsTmp/PRState/31672/PRAgent/try-fix/attempt-1/reviewer-findings.json
  • CustomAgentLogsTmp/PRState/31672/PRAgent/try-fix/attempt-1/analysis.md

Stopped after Candidate #1 because it satisfies the requested stop condition: a candidate passed all targeted tests and is demonstrably better than the PR's fix.


📝 Recommended PR Title & Description

Assessment: ✏️ Recommend updating — the title is good, but the description is stale relative to the winning pr-plus-reviewer fix because it omits the looped initial-position itemCount correction.

Recommended title

[Android] CarouselView: Fix scroll to last item after data reset in loop mode

Recommended description

### Issue Details :

- When the item source is reloaded and items are added dynamically, updating the CurrentItem to one of the last items correctly changes the property, but the carousel fails to visually scroll to that position.

### Root Cause:

- When ScrollToPosition(carouselPosition) was called with a logical position like 0 (i.e., the CarouselView position), it scrolled to the raw adapter position 0. However, position 0 in the virtualized array represented the beginning of the full range, which was not the correct location for proper looping behavior. As a result, the center position was set to 0. Then, when attempting to scroll backward, the logic subtracted the target item index from this center position (0), leading to negative values.
- This caused the scroll operation to fail, and no scrolling took place.
- The looped initial-position path also needs to source the loop item count from the adapter for all looped initial positions; otherwise Loop=true with Position > 0 and no CurrentItem can update CurrentItem without visually centering the RecyclerView.

### Description of Change

- Updated GetGoToIndex in CarouselViewLoopManager.cs to correctly handle empty item sources and invalid target positions, and to calculate the nearest valid looped adapter position for determining the shortest scroll path in loop mode.
- Added a new helper method UpdateLoopCentering to MauiCarouselRecyclerView.cs that recalculates and centers the carousel on the correct item when in loop mode, both after collection changes and during initial position updates. This ensures the view is properly centered even after resetting the data or changing the selected item.
- Updated the looped initial-position path to source itemCount from ItemsViewAdapter.ItemsSource.Count before calling UpdateLoopCentering, so initial Position > 0 works even when CurrentItem is not set.

### Issues Fixed
Fixes #23023

### Validated the behaviour in the following platforms

- [ ] Windows - Test fails on Windows — tracked in #[31670](https://github.com/dotnet/maui/issues/31670)
- [x] Android
- [x] iOS
- [x] Mac

### Output
| Before | After |
|----------|----------|
| <video src="https://github.com/user-attachments/assets/48e2f114-1816-4834-a27a-a3089031d967"> | <video src="https://github.com/user-attachments/assets/f405d814-07ac-4f9e-b2af-2f48669c4878"> |

🏁 Report — Final Recommendation

Comparative Report - PR #31672

Candidates Compared

Rank Candidate Test / Review Status Assessment
1 pr-plus-reviewer Android gate inherited from PR: pass. Expert reviewer finding addressed in sandbox. Best overall. Keeps the PR's nearest looped adapter-position calculation and reset recentering, and fixes the remaining Loop=true, initial Position>0, CurrentItem=null centering gap.
2 try-fix-1 Android Issue23023 test: pass. Self-review: 0 findings. Good simpler alternative. It fixes stale loop-manager source and sources loop item count from the adapter for all looped initial positions, but it keeps the older scroll-distance calculation instead of the PR's more direct nearest adapter-position search.
3 pr Supplied Android gate: pass. Expert review: major issue. Fixes the target reset scenario but leaves a regression where looped Android carousels initialized with Position>0 and no CurrentItem can report the requested item without visually centering.

Candidate Details

pr

The raw PR changes CarouselViewLoopManager.GetGoToIndex to select the nearest valid looped adapter position and adds UpdateLoopCentering so reset and initial-position paths jump to the centered loop range instead of raw adapter positions. This directly matches #23023 and the supplied gate passed. It is ranked below passing alternatives because the expert reviewer found that UpdateInitialPosition() can still call UpdateLoopCentering(0) for initial looped Position>0 with no CurrentItem.

pr-plus-reviewer

This candidate applies the expert reviewer feedback in a sandbox copy by sourcing itemCount from ItemsViewAdapter.ItemsSource.Count whenever the Carousel.Loop path calls UpdateLoopCentering. That closes the raw PR's remaining initialization gap while preserving the PR's more robust nearest-adapter-position approach for explicit scroll requests after data reset.

try-fix-1

This candidate avoids the new GetNearestAdapterPosition and UpdateLoopCentering helpers, keeping the existing scroll flow with targeted corrections: sync the loop manager source after adapter rebuild, convert reset scrolls to looped adapter positions, and source loop item count from the adapter during initialization. It passed the Android regression test and is simpler, but it does not improve the explicit scroll target calculation as much as the PR's nearest-position helper.

Winning Candidate

Winner: pr-plus-reviewer

pr-plus-reviewer wins because it preserves the PR's passing fix for #23023, retains the more robust nearest looped adapter-position calculation, and incorporates the expert reviewer's required correction for looped initial Position>0. The raw PR is ranked lower because it has an unresolved major code-review regression; try-fix-1 is a viable fallback but provides a narrower fix than the reviewed PR plus targeted correction.


🧭 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 Jun 30, 2026
@kubaflo

kubaflo commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

/azp run

@azure-pipelines

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

@kubaflo
kubaflo changed the base branch from main to inflight/current July 5, 2026 16:43
@kubaflo
kubaflo merged commit d598800 into dotnet:inflight/current Jul 5, 2026
153 of 164 checks passed
@github-actions github-actions Bot added this to the .NET 10 SR9 milestone Jul 5, 2026
@kubaflo kubaflo mentioned this pull request Jul 6, 2026
kubaflo pushed a commit that referenced this pull request Jul 6, 2026
…oop mode (#31672)

<!-- Please let the below note in for people that find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!

### Issue Details :

- When the item source is reloaded and items are added dynamically,
updating the CurrentItem to one of the last items correctly changes the
property, but the carousel fails to visually scroll to that position.

### Root Cause:

- When ScrollToPosition(carouselPosition) was called with a logical
position like 0 (i.e., the CarouselView position), it scrolled to the
raw adapter position 0. However, position 0 in the virtualized array
represented the beginning of the full range, which was not the correct
location for proper looping behavior. As a result, the center position
was set to 0. Then, when attempting to scroll backward, the logic
subtracted the target item index from this center position (0), leading
to negative values.
- This caused the scroll operation to fail, and no scrolling took place.

### Description of Change

- Updated GetGoToIndex in CarouselViewLoopManager.cs to correctly handle
empty item sources and fix the calculation for determining the shortest
scroll path in loop mode.
- Added a new helper method UpdateLoopCentering to
MauiCarouselRecyclerView.cs that recalculates and centers the carousel
on the correct item when in loop mode, both after collection changes and
during initial position updates. This ensures the view is properly
centered even after resetting the data or changing the selected item.

### Issues Fixed
Fixes #23023

### Validated the behaviour in the following platforms

- [ ] Windows - Test fails on Windows — tracked in
#[31670](#31670)
- [x] Android
- [x] iOS
- [x] Mac

### Output
| Before | After |
|----------|----------|
| <video
src="https://github.com/user-attachments/assets/48e2f114-1816-4834-a27a-a3089031d967">
| <video
src="https://github.com/user-attachments/assets/f405d814-07ac-4f9e-b2af-2f48669c4878">
|
PureWeen pushed a commit that referenced this pull request Jul 7, 2026
…oop mode (#31672)

<!-- Please let the below note in for people that find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!

### Issue Details :

- When the item source is reloaded and items are added dynamically,
updating the CurrentItem to one of the last items correctly changes the
property, but the carousel fails to visually scroll to that position.

### Root Cause:

- When ScrollToPosition(carouselPosition) was called with a logical
position like 0 (i.e., the CarouselView position), it scrolled to the
raw adapter position 0. However, position 0 in the virtualized array
represented the beginning of the full range, which was not the correct
location for proper looping behavior. As a result, the center position
was set to 0. Then, when attempting to scroll backward, the logic
subtracted the target item index from this center position (0), leading
to negative values.
- This caused the scroll operation to fail, and no scrolling took place.

### Description of Change

- Updated GetGoToIndex in CarouselViewLoopManager.cs to correctly handle
empty item sources and fix the calculation for determining the shortest
scroll path in loop mode.
- Added a new helper method UpdateLoopCentering to
MauiCarouselRecyclerView.cs that recalculates and centers the carousel
on the correct item when in loop mode, both after collection changes and
during initial position updates. This ensures the view is properly
centered even after resetting the data or changing the selected item.

### Issues Fixed
Fixes #23023

### Validated the behaviour in the following platforms

- [ ] Windows - Test fails on Windows — tracked in
#[31670](#31670)
- [x] Android
- [x] iOS
- [x] Mac

### Output
| Before | After |
|----------|----------|
| <video
src="https://github.com/user-attachments/assets/48e2f114-1816-4834-a27a-a3089031d967">
| <video
src="https://github.com/user-attachments/assets/f405d814-07ac-4f9e-b2af-2f48669c4878">
|
PureWeen pushed a commit that referenced this pull request Jul 7, 2026
…oop mode (#31672)

<!-- Please let the below note in for people that find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!

### Issue Details :

- When the item source is reloaded and items are added dynamically,
updating the CurrentItem to one of the last items correctly changes the
property, but the carousel fails to visually scroll to that position.

### Root Cause:

- When ScrollToPosition(carouselPosition) was called with a logical
position like 0 (i.e., the CarouselView position), it scrolled to the
raw adapter position 0. However, position 0 in the virtualized array
represented the beginning of the full range, which was not the correct
location for proper looping behavior. As a result, the center position
was set to 0. Then, when attempting to scroll backward, the logic
subtracted the target item index from this center position (0), leading
to negative values.
- This caused the scroll operation to fail, and no scrolling took place.

### Description of Change

- Updated GetGoToIndex in CarouselViewLoopManager.cs to correctly handle
empty item sources and fix the calculation for determining the shortest
scroll path in loop mode.
- Added a new helper method UpdateLoopCentering to
MauiCarouselRecyclerView.cs that recalculates and centers the carousel
on the correct item when in loop mode, both after collection changes and
during initial position updates. This ensures the view is properly
centered even after resetting the data or changing the selected item.

### Issues Fixed
Fixes #23023

### Validated the behaviour in the following platforms

- [ ] Windows - Test fails on Windows — tracked in
#[31670](#31670)
- [x] Android
- [x] iOS
- [x] Mac

### Output
| Before | After |
|----------|----------|
| <video
src="https://github.com/user-attachments/assets/48e2f114-1816-4834-a27a-a3089031d967">
| <video
src="https://github.com/user-attachments/assets/f405d814-07ac-4f9e-b2af-2f48669c4878">
|
kubaflo pushed a commit that referenced this pull request Jul 10, 2026
…oop mode (#31672)

<!-- Please let the below note in for people that find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!

### Issue Details :

- When the item source is reloaded and items are added dynamically,
updating the CurrentItem to one of the last items correctly changes the
property, but the carousel fails to visually scroll to that position.

### Root Cause:

- When ScrollToPosition(carouselPosition) was called with a logical
position like 0 (i.e., the CarouselView position), it scrolled to the
raw adapter position 0. However, position 0 in the virtualized array
represented the beginning of the full range, which was not the correct
location for proper looping behavior. As a result, the center position
was set to 0. Then, when attempting to scroll backward, the logic
subtracted the target item index from this center position (0), leading
to negative values.
- This caused the scroll operation to fail, and no scrolling took place.

### Description of Change

- Updated GetGoToIndex in CarouselViewLoopManager.cs to correctly handle
empty item sources and fix the calculation for determining the shortest
scroll path in loop mode.
- Added a new helper method UpdateLoopCentering to
MauiCarouselRecyclerView.cs that recalculates and centers the carousel
on the correct item when in loop mode, both after collection changes and
during initial position updates. This ensures the view is properly
centered even after resetting the data or changing the selected item.

### Issues Fixed
Fixes #23023

### Validated the behaviour in the following platforms

- [ ] Windows - Test fails on Windows — tracked in
#[31670](#31670)
- [x] Android
- [x] iOS
- [x] Mac

### Output
| Before | After |
|----------|----------|
| <video
src="https://github.com/user-attachments/assets/48e2f114-1816-4834-a27a-a3089031d967">
| <video
src="https://github.com/user-attachments/assets/f405d814-07ac-4f9e-b2af-2f48669c4878">
|
kubaflo pushed a commit that referenced this pull request Jul 15, 2026
…oop mode (#31672)

<!-- Please let the below note in for people that find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!

### Issue Details :

- When the item source is reloaded and items are added dynamically,
updating the CurrentItem to one of the last items correctly changes the
property, but the carousel fails to visually scroll to that position.

### Root Cause:

- When ScrollToPosition(carouselPosition) was called with a logical
position like 0 (i.e., the CarouselView position), it scrolled to the
raw adapter position 0. However, position 0 in the virtualized array
represented the beginning of the full range, which was not the correct
location for proper looping behavior. As a result, the center position
was set to 0. Then, when attempting to scroll backward, the logic
subtracted the target item index from this center position (0), leading
to negative values.
- This caused the scroll operation to fail, and no scrolling took place.

### Description of Change

- Updated GetGoToIndex in CarouselViewLoopManager.cs to correctly handle
empty item sources and fix the calculation for determining the shortest
scroll path in loop mode.
- Added a new helper method UpdateLoopCentering to
MauiCarouselRecyclerView.cs that recalculates and centers the carousel
on the correct item when in loop mode, both after collection changes and
during initial position updates. This ensures the view is properly
centered even after resetting the data or changing the selected item.

### Issues Fixed
Fixes #23023

### Validated the behaviour in the following platforms

- [ ] Windows - Test fails on Windows — tracked in
#[31670](#31670)
- [x] Android
- [x] iOS
- [x] Mac

### Output
| Before | After |
|----------|----------|
| <video
src="https://github.com/user-attachments/assets/48e2f114-1816-4834-a27a-a3089031d967">
| <video
src="https://github.com/user-attachments/assets/f405d814-07ac-4f9e-b2af-2f48669c4878">
|
kubaflo pushed a commit that referenced this pull request Jul 22, 2026
…oop mode (#31672)

<!-- Please let the below note in for people that find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!

### Issue Details :

- When the item source is reloaded and items are added dynamically,
updating the CurrentItem to one of the last items correctly changes the
property, but the carousel fails to visually scroll to that position.

### Root Cause:

- When ScrollToPosition(carouselPosition) was called with a logical
position like 0 (i.e., the CarouselView position), it scrolled to the
raw adapter position 0. However, position 0 in the virtualized array
represented the beginning of the full range, which was not the correct
location for proper looping behavior. As a result, the center position
was set to 0. Then, when attempting to scroll backward, the logic
subtracted the target item index from this center position (0), leading
to negative values.
- This caused the scroll operation to fail, and no scrolling took place.

### Description of Change

- Updated GetGoToIndex in CarouselViewLoopManager.cs to correctly handle
empty item sources and fix the calculation for determining the shortest
scroll path in loop mode.
- Added a new helper method UpdateLoopCentering to
MauiCarouselRecyclerView.cs that recalculates and centers the carousel
on the correct item when in loop mode, both after collection changes and
during initial position updates. This ensures the view is properly
centered even after resetting the data or changing the selected item.

### Issues Fixed
Fixes #23023

### Validated the behaviour in the following platforms

- [ ] Windows - Test fails on Windows — tracked in
#[31670](#31670)
- [x] Android
- [x] iOS
- [x] Mac

### Output
| Before | After |
|----------|----------|
| <video
src="https://github.com/user-attachments/assets/48e2f114-1816-4834-a27a-a3089031d967">
| <video
src="https://github.com/user-attachments/assets/f405d814-07ac-4f9e-b2af-2f48669c4878">
|
kubaflo pushed a commit that referenced this pull request Jul 28, 2026
…oop mode (#31672)

<!-- Please let the below note in for people that find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!

### Issue Details :

- When the item source is reloaded and items are added dynamically,
updating the CurrentItem to one of the last items correctly changes the
property, but the carousel fails to visually scroll to that position.

### Root Cause:

- When ScrollToPosition(carouselPosition) was called with a logical
position like 0 (i.e., the CarouselView position), it scrolled to the
raw adapter position 0. However, position 0 in the virtualized array
represented the beginning of the full range, which was not the correct
location for proper looping behavior. As a result, the center position
was set to 0. Then, when attempting to scroll backward, the logic
subtracted the target item index from this center position (0), leading
to negative values.
- This caused the scroll operation to fail, and no scrolling took place.

### Description of Change

- Updated GetGoToIndex in CarouselViewLoopManager.cs to correctly handle
empty item sources and fix the calculation for determining the shortest
scroll path in loop mode.
- Added a new helper method UpdateLoopCentering to
MauiCarouselRecyclerView.cs that recalculates and centers the carousel
on the correct item when in loop mode, both after collection changes and
during initial position updates. This ensures the view is properly
centered even after resetting the data or changing the selected item.

### Issues Fixed
Fixes #23023

### Validated the behaviour in the following platforms

- [ ] Windows - Test fails on Windows — tracked in
#[31670](#31670)
- [x] Android
- [x] iOS
- [x] Mac

### Output
| Before | After |
|----------|----------|
| <video
src="https://github.com/user-attachments/assets/48e2f114-1816-4834-a27a-a3089031d967">
| <video
src="https://github.com/user-attachments/assets/f405d814-07ac-4f9e-b2af-2f48669c4878">
|
kubaflo pushed a commit that referenced this pull request Jul 29, 2026
…oop mode (#31672)

<!-- Please let the below note in for people that find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!

### Issue Details :

- When the item source is reloaded and items are added dynamically,
updating the CurrentItem to one of the last items correctly changes the
property, but the carousel fails to visually scroll to that position.

### Root Cause:

- When ScrollToPosition(carouselPosition) was called with a logical
position like 0 (i.e., the CarouselView position), it scrolled to the
raw adapter position 0. However, position 0 in the virtualized array
represented the beginning of the full range, which was not the correct
location for proper looping behavior. As a result, the center position
was set to 0. Then, when attempting to scroll backward, the logic
subtracted the target item index from this center position (0), leading
to negative values.
- This caused the scroll operation to fail, and no scrolling took place.

### Description of Change

- Updated GetGoToIndex in CarouselViewLoopManager.cs to correctly handle
empty item sources and fix the calculation for determining the shortest
scroll path in loop mode.
- Added a new helper method UpdateLoopCentering to
MauiCarouselRecyclerView.cs that recalculates and centers the carousel
on the correct item when in loop mode, both after collection changes and
during initial position updates. This ensures the view is properly
centered even after resetting the data or changing the selected item.

### Issues Fixed
Fixes #23023

### Validated the behaviour in the following platforms

- [ ] Windows - Test fails on Windows — tracked in
#[31670](#31670)
- [x] Android
- [x] iOS
- [x] Mac

### Output
| Before | After |
|----------|----------|
| <video
src="https://github.com/user-attachments/assets/48e2f114-1816-4834-a27a-a3089031d967">
| <video
src="https://github.com/user-attachments/assets/f405d814-07ac-4f9e-b2af-2f48669c4878">
|
@github-actions github-actions Bot locked and limited conversation to collaborators Aug 5, 2026
@github-actions github-actions Bot modified the milestones: .NET 10 SR9, .NET 10 SR10 Aug 20, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

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.

[Android] CarouselView many issues with CurrentItem bindings

7 participants