Repository navigation
[Android] CarouselView: Fix scroll to last item after data reset in loop mode - #31672
Conversation
|
/azp run |
|
Azure Pipelines successfully started running 3 pipeline(s). |
There was a problem hiding this comment.
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). |
|
/azp run |
|
Azure Pipelines successfully started running 3 pipeline(s). |
3d669d3 to
82ec14c
Compare
|
🚀 Dogfood this PR with:
curl -fsSL https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.sh | bash -s -- 31672Or
iex "& { $(irm https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.ps1) } 31672" |
|
Addressed concerns raised in the AI summary. |
@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.
|
|
/azp run maui-pr-uitests |
|
Azure Pipelines successfully started running 1 pipeline(s). |
|
Azure Pipelines successfully started running 3 pipeline(s). |
| if (Carousel.Loop) | ||
| { | ||
| UpdateLoopCentering(itemCount); | ||
| } |
There was a problem hiding this comment.
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.
This comment has been minimized.
This comment has been minimized.
MauiBot
left a comment
There was a problem hiding this comment.
Expert Review — 1 findings
See inline comments for details.
| ScrollHelper.JumpScrollToPosition(index, Microsoft.Maui.Controls.ScrollToPosition.Center); | ||
| if (Carousel.Loop) | ||
| { | ||
| UpdateLoopCentering(itemCount); |
There was a problem hiding this comment.
🔍 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
left a comment
There was a problem hiding this comment.
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.
🗂️ 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.cssrc/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
CarouselViewloop mode: after reloading a source with more than about six items and selecting an end item,CurrentItemchanges but the visible item remains at the start. - PR #31672 changes Android
CarouselViewloop 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
newPositionbounds 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 initialPosition > 0with noCurrentItemcan skip loop centering becauseitemCountremains0, causingUpdateLoopCenteringto return without scrolling. - Failure mode:
Loop=true,Position=0works;Loop=true,Position>0,CurrentItem=nullsets_oldPosition/CurrentItembut does not scroll;CurrentItem-initialized looped carousel works if the item is found. - Blast radius: Android
CarouselViewloop-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
CarouselViewloop-mode paths only. - Startup impact: Yes, for looped Android
CarouselViewinitial positioning. - Static/shared state: No new static/shared state.
CI Status
- Required-check result:
gh pr checks --requiredcould not run becauseghis unauthenticated in this environment. - Supplemental check result: Public check-runs show
maui-pr/Build Analysisfailing on head SHAb77d26a, 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:itemCountis populated and centering works. - Initial looped carousel with
Position>0and noCurrentItem:itemCountremains 0; no scroll occurs. - Initial looped carousel with
CurrentItemset: enumeration populatesitemCount; 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.
VerifyCarouselScrollsToEndItemAfterResetpassed on Android emulatoremulator-5554.- Test run successful: 1 total, 1 passed.
Full attempt artifacts:
CustomAgentLogsTmp/PRState/31672/PRAgent/try-fix/attempt-1/approach.mdCustomAgentLogsTmp/PRState/31672/PRAgent/try-fix/attempt-1/fix.diffCustomAgentLogsTmp/PRState/31672/PRAgent/try-fix/attempt-1/test-output.logCustomAgentLogsTmp/PRState/31672/PRAgent/try-fix/attempt-1/reviewer-findings.jsonCustomAgentLogsTmp/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.
|
/azp run |
|
Azure Pipelines successfully started running 3 pipeline(s). |
…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"> |
…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"> |
…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"> |
…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"> |
…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"> |
…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"> |
…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"> |
…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"> |


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 :
Root Cause:
Description of Change
Issues Fixed
Fixes #23023
Validated the behaviour in the following platforms
Output
Before.mov
After.mov