Skip to content

[iOS/Mac][CV2] Fix CarouselView2 freezes with infinite loop when IsScrollAnimated=False - #35848

Merged
kubaflo merged 2 commits into
dotnet:inflight/currentfrom
SyedAbdulAzeemSF4852:fix-35675
Jun 22, 2026
Merged

[iOS/Mac][CV2] Fix CarouselView2 freezes with infinite loop when IsScrollAnimated=False#35848
kubaflo merged 2 commits into
dotnet:inflight/currentfrom
SyedAbdulAzeemSF4852:fix-35675

Conversation

@SyedAbdulAzeemSF4852

@SyedAbdulAzeemSF4852 SyedAbdulAzeemSF4852 commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Note

Are you waiting for the changes in this PR to be merged?
It would be very helpful if you could test the resulting artifacts from this PR and let us know in a comment if this change resolves your issue. Thank you!

Issue Details

  • CarouselView2 (CV2) on iOS freezes with an infinite loop when ItemsSource is swapped and CurrentItem is set programmatically with IsScrollAnimated=False — the app becomes completely unresponsive.

Root Cause

  • When IsScrollAnimated=False, UICollectionView.ScrollToItem(animated:false) fires scroll callbacks synchronously, causing the scroll logic to re-enter itself indefinitely and making the app completely unresponsive.

Description of Change

  • Added a _gotoPosition field to CarouselViewController2 to track the intended scroll target and suppress intermediate position updates during scrolls, preventing infinite loops when IsScrollAnimated is false.

  • Reference => SetPosition (CarouselViewController)

  • Additionally added the missing _gotoPosition cleanup paths:

    • Clear _gotoPosition in CollectionViewUpdated when the collection changes.
    • Guard ScrollToPosition to skip if a scroll is already in-flight.
    • Clear _gotoPosition in UpdateFromCurrentItem when the animated scroll lands at the intended position.

Issues Fixed

Fixes #35675

Validated the behaviour in the following platforms

  • Windows
  • Android
  • iOS
  • Mac

Output

Before After
Before_Fix.mov
After_Fix.mov

@github-actions

github-actions Bot commented Jun 10, 2026

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

Or

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

@NirmalKumarYuvaraj NirmalKumarYuvaraj added area-controls-collectionview CollectionView, CarouselView, IndicatorView community ✨ Community Contribution collectionview-cv2 partner/syncfusion Issues / PR's with Syncfusion collaboration labels Jun 10, 2026
@SyedAbdulAzeemSF4852 SyedAbdulAzeemSF4852 changed the title [WIP][iOS/Mac][CV2] Fix CarouselView2 freezes with infinite loop when IsScrollAnimated=False [iOS/Mac][CV2] Fix CarouselView2 freezes with infinite loop when IsScrollAnimated=False Jun 15, 2026
@sheiksyedm
sheiksyedm marked this pull request as ready for review June 15, 2026 17:06
@MauiBot MauiBot added s/agent-fix-win AI found a better alternative fix than the PR s/agent-reviewed PR was reviewed by AI agent workflow (full 4-phase review) labels Jun 18, 2026
MauiBot

This comment was marked as outdated.

@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 21, 2026

@MauiBot MauiBot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Expert Review — 2 findings

See inline comments for details.

bool _isInternalCollectionUpdate = false;
int _section = 0;
bool _wasDetachedFromWindow = false;
int _gotoPosition = -1;

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.

⚠️ Warning: _gotoPosition is new lifecycle state but it is not reset in teardown/dispose or ItemsSource replacement/empty-source paths. If the CarouselView detaches while a programmatic scroll is pending, the stale target can survive reattach and cause SetPosition to suppress valid positions for the new view/source. Please clear this with the other lifecycle flags.

}

if (goToPosition != carouselPosition || forceScroll)
if (_gotoPosition == -1 && (goToPosition != carouselPosition || forceScroll))

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.

⚠️ Warning: this guard drops any newer programmatic scroll request while a previous _gotoPosition is pending. For example, setting CurrentItem/Position twice before UIKit reports the first target means the second ScrollToPosition no-ops, then the first callback can publish the stale item/position. Consider replacing the pending target when the requested target changes instead of ignoring it.

@MauiBot MauiBot added s/agent-gate-passed AI verified tests catch the bug (fail without fix, pass with fix) s/agent-fix-pr-picked AI could not beat the PR fix - PR is the best among all candidates and removed s/agent-fix-win AI found a better alternative fix than the PR labels Jun 21, 2026
MauiBot

This comment was marked as outdated.

@MauiBot MauiBot removed the s/agent-review-in-progress AI review is currently running for this PR label Jun 22, 2026
@MauiBot MauiBot added s/agent-fix-win AI found a better alternative fix than the PR and removed s/agent-fix-pr-picked AI could not beat the PR fix - PR is the best among all candidates labels Jun 22, 2026
@kubaflo
kubaflo changed the base branch from main to inflight/current June 22, 2026 13:23
@kubaflo
kubaflo merged commit 9c150cb into dotnet:inflight/current Jun 22, 2026
33 checks passed
@github-actions github-actions Bot added this to the .NET 10 SR9 milestone Jun 22, 2026

@MauiBot MauiBot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

AI Review Summary

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

Gate Passed Confidence Low Platform iOS


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

Gate Result: ✅ PASSED

Platform: IOS · Base: main · Merge base: 4567a055

Test Without Fix (expect FAIL) With Fix (expect PASS)
🖥️ Issue35675 Issue35675 ✅ FAIL — 710s ✅ PASS — 119s
🔴 Without fix — 🖥️ Issue35675: FAIL ✅ · 710s
  Determining projects to restore...
  Restored /Users/cloudtest/vss/_work/1/s/src/Controls/src/BindingSourceGen/Controls.BindingSourceGen.csproj (in 702 ms).
  Restored /Users/cloudtest/vss/_work/1/s/src/Graphics/src/Graphics/Graphics.csproj (in 722 ms).
  Restored /Users/cloudtest/vss/_work/1/s/src/Essentials/src/Essentials.csproj (in 5.23 sec).
  Restored /Users/cloudtest/vss/_work/1/s/src/Controls/Foldable/src/Controls.Foldable.csproj (in 6.89 sec).
  Restored /Users/cloudtest/vss/_work/1/s/src/BlazorWebView/src/Maui/Microsoft.AspNetCore.Components.WebView.Maui.csproj (in 6.16 sec).
  Restored /Users/cloudtest/vss/_work/1/s/src/Controls/src/Core/Controls.Core.csproj (in 6.9 sec).
  Restored /Users/cloudtest/vss/_work/1/s/src/Controls/Maps/src/Controls.Maps.csproj (in 6.9 sec).
  Restored /Users/cloudtest/vss/_work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj (in 6.9 sec).
  Restored /Users/cloudtest/vss/_work/1/s/src/Controls/src/Xaml/Controls.Xaml.csproj (in 6.9 sec).
  Restored /Users/cloudtest/vss/_work/1/s/src/Core/maps/src/Maps.csproj (in 6.92 sec).
  Restored /Users/cloudtest/vss/_work/1/s/src/Core/src/Core.csproj (in 6.93 sec).
/Users/cloudtest/vss/_work/1/s/.dotnet/packs/Microsoft.iOS.Sdk.net10.0_26.0/26.0.11017/targets/Xamarin.Shared.Sdk.targets(309,3): warning : RuntimeIdentifier was set on the command line, and will override the value for RuntimeIdentifiers set in the project file. [/Users/cloudtest/vss/_work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-ios]
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14445925
  Graphics -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Graphics/Debug/net10.0-ios26.0/Microsoft.Maui.Graphics.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14445925
  Essentials -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Essentials/Debug/net10.0-ios26.0/Microsoft.Maui.Essentials.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14445925
  Core -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Core/Debug/net10.0-ios26.0/Microsoft.Maui.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14445925
  Maps -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Maps/Debug/net10.0-ios26.0/Microsoft.Maui.Maps.dll
  Controls.BindingSourceGen -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.BindingSourceGen/Debug/netstandard2.0/Microsoft.Maui.Controls.BindingSourceGen.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14445925
  Controls.Core -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.Core/Debug/net10.0-ios26.0/Microsoft.Maui.Controls.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14445925
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14445925
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14445925
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14445925
  Controls.Xaml -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.Xaml/Debug/net10.0-ios26.0/Microsoft.Maui.Controls.Xaml.dll
  Controls.Foldable -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.Foldable/Debug/net10.0-ios26.0/Microsoft.Maui.Controls.Foldable.dll
  Microsoft.AspNetCore.Components.WebView.Maui -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Microsoft.AspNetCore.Components.WebView.Maui/Debug/net10.0-ios26.0/Microsoft.AspNetCore.Components.WebView.Maui.dll
  Controls.Maps -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.Maps/Debug/net10.0-ios26.0/Microsoft.Maui.Controls.Maps.dll
  Detected signing identity:
    Code Signing Key: "" (-)
    Provisioning Profile: "" () - no entitlements
    Bundle Id: com.microsoft.maui.uitests
    App Id: com.microsoft.maui.uitests
  Controls.TestCases.HostApp -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-ios/iossimulator-arm64/Controls.TestCases.HostApp.dll
  Optimizing assemblies for size may change the behavior of the app. Be sure to test after publishing. See: https://aka.ms/dotnet-illink
  Optimizing assemblies for size. This process might take a while.

Build succeeded.

/Users/cloudtest/vss/_work/1/s/.dotnet/packs/Microsoft.iOS.Sdk.net10.0_26.0/26.0.11017/targets/Xamarin.Shared.Sdk.targets(309,3): warning : RuntimeIdentifier was set on the command line, and will override the value for RuntimeIdentifiers set in the project file. [/Users/cloudtest/vss/_work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-ios]
    1 Warning(s)
    0 Error(s)

Time Elapsed 00:03:10.14
  Determining projects to restore...
  Restored /Users/cloudtest/vss/_work/1/s/src/Controls/tests/CustomAttributes/Controls.CustomAttributes.csproj (in 784 ms).
  Restored /Users/cloudtest/vss/_work/1/s/src/Graphics/src/Graphics/Graphics.csproj (in 784 ms).
  Restored /Users/cloudtest/vss/_work/1/s/src/Controls/src/BindingSourceGen/Controls.BindingSourceGen.csproj (in 788 ms).
  Restored /Users/cloudtest/vss/_work/1/s/src/TestUtils/src/VisualTestUtils/VisualTestUtils.csproj (in 788 ms).
  Restored /Users/cloudtest/vss/_work/1/s/src/Essentials/src/Essentials.csproj (in 824 ms).
  Restored /Users/cloudtest/vss/_work/1/s/src/TestUtils/src/UITest.Core/UITest.Core.csproj (in 1 ms).
  Restored /Users/cloudtest/vss/_work/1/s/src/Core/src/Core.csproj (in 922 ms).
  Restored /Users/cloudtest/vss/_work/1/s/src/Controls/src/Core/Controls.Core.csproj (in 205 ms).
  Restored /Users/cloudtest/vss/_work/1/s/src/TestUtils/src/UITest.NUnit/UITest.NUnit.csproj (in 1.08 sec).
  Restored /Users/cloudtest/vss/_work/1/s/src/TestUtils/src/UITest.Appium/UITest.Appium.csproj (in 2.92 sec).
  Restored /Users/cloudtest/vss/_work/1/s/src/TestUtils/src/UITest.Analyzers/UITest.Analyzers.csproj (in 4.17 sec).
  Restored /Users/cloudtest/vss/_work/1/s/src/TestUtils/src/VisualTestUtils.MagickNet/VisualTestUtils.MagickNet.csproj (in 5.74 sec).
  Restored /Users/cloudtest/vss/_work/1/s/src/Controls/tests/TestCases.iOS.Tests/Controls.TestCases.iOS.Tests.csproj (in 6.6 sec).
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14445925
  Controls.CustomAttributes -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.CustomAttributes/Debug/net10.0/Controls.CustomAttributes.dll
  Graphics -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Graphics/Debug/net10.0/Microsoft.Maui.Graphics.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14445925
  Essentials -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Essentials/Debug/net10.0/Microsoft.Maui.Essentials.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14445925
  Core -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Core/Debug/net10.0/Microsoft.Maui.dll
  Controls.BindingSourceGen -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.BindingSourceGen/Debug/netstandard2.0/Microsoft.Maui.Controls.BindingSourceGen.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14445925
  Controls.Core -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.Core/Debug/net10.0/Microsoft.Maui.Controls.dll
  VisualTestUtils -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/VisualTestUtils/Debug/netstandard2.0/VisualTestUtils.dll
  UITest.Core -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/UITest.Core/Debug/net10.0/UITest.Core.dll
  VisualTestUtils.MagickNet -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/VisualTestUtils.MagickNet/Debug/netstandard2.0/VisualTestUtils.MagickNet.dll
  UITest.NUnit -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/UITest.NUnit/Debug/net10.0/UITest.NUnit.dll
  UITest.Appium -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/UITest.Appium/Debug/net10.0/UITest.Appium.dll
  UITest.Analyzers -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/UITest.Analyzers/Debug/netstandard2.0/UITest.Analyzers.dll
  Controls.TestCases.iOS.Tests -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.TestCases.iOS.Tests/Debug/net10.0/Controls.TestCases.iOS.Tests.dll
Test run for /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.TestCases.iOS.Tests/Debug/net10.0/Controls.TestCases.iOS.Tests.dll (.NETCoreApp,Version=v10.0)
VSTest version 18.0.1 (arm64)

Starting test execution, please wait...
A total of 1 test files matched the specified pattern.
[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.07]   Discovering: Controls.TestCases.iOS.Tests
[xUnit.net 00:00:00.21]   Discovered:  Controls.TestCases.iOS.Tests
NUnit Adapter 4.5.0.0: Test execution started
Running selected tests in /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.TestCases.iOS.Tests/Debug/net10.0/Controls.TestCases.iOS.Tests.dll
   NUnit3TestExecutor discovered 1 of 1 NUnit test cases using Current Discovery mode, Non-Explicit run
>>>>> 6/22/2026 5:53:24 AM FixtureSetup for Issue35675(iOS)
>>>>> 6/22/2026 5:53:29 AM CV2DoesNotFreezeWhenSettingCurrentItemWithIsScrollAnimatedFalse Start
>>>>> 6/22/2026 5:57:37 AM CV2DoesNotFreezeWhenSettingCurrentItemWithIsScrollAnimatedFalse Stop
>>>>> 6/22/2026 5:57:37 AM Log types: syslog, crashlog, performance, safariConsole, safariNetwork, server
>>>>> 6/22/2026 5:57:52 AM SaveUIDiagnosticInfo timed out — app may be unresponsive, skipping UI diagnostics
  Failed CV2DoesNotFreezeWhenSettingCurrentItemWithIsScrollAnimatedFalse [4 m 22 s]
  Error Message:
   System.TimeoutException : Timed out waiting for element...
  Stack Trace:
     at UITest.Appium.HelperExtensions.Wait(Func`1 query, Func`2 satisfactory, String timeoutMessage, Nullable`1 timeout, Nullable`1 retryFrequency) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 2757
   at UITest.Appium.HelperExtensions.WaitForAtLeastOne(Func`1 query, String timeoutMessage, Nullable`1 timeout, Nullable`1 retryFrequency) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 2784
   at UITest.Appium.HelperExtensions.WaitForElement(IApp app, String marked, String timeoutMessage, Nullable`1 timeout, Nullable`1 retryFrequency, Nullable`1 postTimeout) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 793
   at Microsoft.Maui.TestCases.Tests.Issues.Issue35675.CV2DoesNotFreezeWhenSettingCurrentItemWithIsScrollAnimatedFalse() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue35675.cs:line 24
   at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
   at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)

  Standard Error Messages:
 >>>>> 6/22/2026 5:57:52 AM SaveUIDiagnosticInfo timed out — app may be unresponsive, skipping UI diagnostics

NUnit Adapter 4.5.0.0: Test execution complete
Results File: /Users/cloudtest/vss/_work/1/s/CustomAgentLogsTmp/UITests/TestResults/Issue35675.trx

Test Run Failed.
Total tests: 1
     Failed: 1
 Total time: 7.6718 Minutes
>>> TRX_RESULT_FILE: /Users/cloudtest/vss/_work/1/s/CustomAgentLogsTmp/UITests/TestResults/Issue35675.trx

🟢 With fix — 🖥️ Issue35675: PASS ✅ · 119s
  Determining projects to restore...
  Restored /Users/cloudtest/vss/_work/1/s/src/Controls/src/BindingSourceGen/Controls.BindingSourceGen.csproj (in 425 ms).
  Restored /Users/cloudtest/vss/_work/1/s/src/Graphics/src/Graphics/Graphics.csproj (in 454 ms).
  Restored /Users/cloudtest/vss/_work/1/s/src/Essentials/src/Essentials.csproj (in 414 ms).
  Restored /Users/cloudtest/vss/_work/1/s/src/Controls/src/Core/Controls.Core.csproj (in 508 ms).
  Restored /Users/cloudtest/vss/_work/1/s/src/Core/src/Core.csproj (in 524 ms).
  6 of 11 projects are up-to-date for restore.
/Users/cloudtest/vss/_work/1/s/.dotnet/packs/Microsoft.iOS.Sdk.net10.0_26.0/26.0.11017/targets/Xamarin.Shared.Sdk.targets(309,3): warning : RuntimeIdentifier was set on the command line, and will override the value for RuntimeIdentifiers set in the project file. [/Users/cloudtest/vss/_work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-ios]
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14445925
  Graphics -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Graphics/Debug/net10.0-ios26.0/Microsoft.Maui.Graphics.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14445925
  Essentials -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Essentials/Debug/net10.0-ios26.0/Microsoft.Maui.Essentials.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14445925
  Core -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Core/Debug/net10.0-ios26.0/Microsoft.Maui.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14445925
  Maps -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Maps/Debug/net10.0-ios26.0/Microsoft.Maui.Maps.dll
  Controls.BindingSourceGen -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.BindingSourceGen/Debug/netstandard2.0/Microsoft.Maui.Controls.BindingSourceGen.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14445925
  Controls.Core -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.Core/Debug/net10.0-ios26.0/Microsoft.Maui.Controls.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14445925
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14445925
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14445925
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14445925
  Microsoft.AspNetCore.Components.WebView.Maui -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Microsoft.AspNetCore.Components.WebView.Maui/Debug/net10.0-ios26.0/Microsoft.AspNetCore.Components.WebView.Maui.dll
  Controls.Maps -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.Maps/Debug/net10.0-ios26.0/Microsoft.Maui.Controls.Maps.dll
  Controls.Foldable -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.Foldable/Debug/net10.0-ios26.0/Microsoft.Maui.Controls.Foldable.dll
  Controls.Xaml -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.Xaml/Debug/net10.0-ios26.0/Microsoft.Maui.Controls.Xaml.dll
  Detected signing identity:
    Code Signing Key: "" (-)
    Provisioning Profile: "" () - no entitlements
    Bundle Id: com.microsoft.maui.uitests
    App Id: com.microsoft.maui.uitests
  Controls.TestCases.HostApp -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-ios/iossimulator-arm64/Controls.TestCases.HostApp.dll
  Optimizing assemblies for size may change the behavior of the app. Be sure to test after publishing. See: https://aka.ms/dotnet-illink
  Optimizing assemblies for size. This process might take a while.

Build succeeded.

/Users/cloudtest/vss/_work/1/s/.dotnet/packs/Microsoft.iOS.Sdk.net10.0_26.0/26.0.11017/targets/Xamarin.Shared.Sdk.targets(309,3): warning : RuntimeIdentifier was set on the command line, and will override the value for RuntimeIdentifiers set in the project file. [/Users/cloudtest/vss/_work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-ios]
    1 Warning(s)
    0 Error(s)

Time Elapsed 00:01:01.87
  Determining projects to restore...
  Restored /Users/cloudtest/vss/_work/1/s/src/Controls/src/BindingSourceGen/Controls.BindingSourceGen.csproj (in 368 ms).
  Restored /Users/cloudtest/vss/_work/1/s/src/Graphics/src/Graphics/Graphics.csproj (in 426 ms).
  Restored /Users/cloudtest/vss/_work/1/s/src/Essentials/src/Essentials.csproj (in 426 ms).
  Restored /Users/cloudtest/vss/_work/1/s/src/Controls/src/Core/Controls.Core.csproj (in 461 ms).
  Restored /Users/cloudtest/vss/_work/1/s/src/Core/src/Core.csproj (in 475 ms).
  8 of 13 projects are up-to-date for restore.
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14445925
  Controls.CustomAttributes -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.CustomAttributes/Debug/net10.0/Controls.CustomAttributes.dll
  Graphics -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Graphics/Debug/net10.0/Microsoft.Maui.Graphics.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14445925
  Essentials -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Essentials/Debug/net10.0/Microsoft.Maui.Essentials.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14445925
  Core -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Core/Debug/net10.0/Microsoft.Maui.dll
  Controls.BindingSourceGen -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.BindingSourceGen/Debug/netstandard2.0/Microsoft.Maui.Controls.BindingSourceGen.dll
  ##vso[build.updatebuildnumber]10.0.90-ci+azdo.14445925
  Controls.Core -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.Core/Debug/net10.0/Microsoft.Maui.Controls.dll
  VisualTestUtils -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/VisualTestUtils/Debug/netstandard2.0/VisualTestUtils.dll
  VisualTestUtils.MagickNet -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/VisualTestUtils.MagickNet/Debug/netstandard2.0/VisualTestUtils.MagickNet.dll
  UITest.Core -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/UITest.Core/Debug/net10.0/UITest.Core.dll
  UITest.Appium -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/UITest.Appium/Debug/net10.0/UITest.Appium.dll
  UITest.NUnit -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/UITest.NUnit/Debug/net10.0/UITest.NUnit.dll
  UITest.Analyzers -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/UITest.Analyzers/Debug/netstandard2.0/UITest.Analyzers.dll
  Controls.TestCases.iOS.Tests -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.TestCases.iOS.Tests/Debug/net10.0/Controls.TestCases.iOS.Tests.dll
Test run for /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.TestCases.iOS.Tests/Debug/net10.0/Controls.TestCases.iOS.Tests.dll (.NETCoreApp,Version=v10.0)
VSTest version 18.0.1 (arm64)

Starting test execution, please wait...
A total of 1 test files matched the specified pattern.
[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.06]   Discovering: Controls.TestCases.iOS.Tests
[xUnit.net 00:00:00.19]   Discovered:  Controls.TestCases.iOS.Tests
NUnit Adapter 4.5.0.0: Test execution started
Running selected tests in /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.TestCases.iOS.Tests/Debug/net10.0/Controls.TestCases.iOS.Tests.dll
   NUnit3TestExecutor discovered 1 of 1 NUnit test cases using Current Discovery mode, Non-Explicit run
>>>>> 6/22/2026 6:01:35 AM FixtureSetup for Issue35675(iOS)
>>>>> 6/22/2026 6:01:40 AM CV2DoesNotFreezeWhenSettingCurrentItemWithIsScrollAnimatedFalse Start
>>>>> 6/22/2026 6:01:40 AM CV2DoesNotFreezeWhenSettingCurrentItemWithIsScrollAnimatedFalse Stop
  Passed CV2DoesNotFreezeWhenSettingCurrentItemWithIsScrollAnimatedFalse [891 ms]
NUnit Adapter 4.5.0.0: Test execution complete
Results File: /Users/cloudtest/vss/_work/1/s/CustomAgentLogsTmp/UITests/TestResults/Issue35675.trx

Test Run Successful.
Total tests: 1
     Passed: 1
 Total time: 23.6984 Seconds
>>> TRX_RESULT_FILE: /Users/cloudtest/vss/_work/1/s/CustomAgentLogsTmp/UITests/TestResults/Issue35675.trx

📁 Fix files reverted (1 files)
  • src/Controls/src/Core/Handlers/Items2/iOS/CarouselViewController2.cs

📋 Pre-Flight — Context & Validation

Issue: #35675 - [iOS] CarouselView freezes with infinite loop when IsScrollAnimated=False
PR: #35848 - [iOS/Mac][CV2] Fix CarouselView2 freezes with infinite loop when IsScrollAnimated=False
Platforms Affected: iOS, MacCatalyst
Files Changed: 1 implementation, 2 test

Key Findings

  • PR changes the active iOS/MacCatalyst Items2 CarouselView handler (src/Controls/src/Core/Handlers/Items2/iOS/CarouselViewController2.cs) and adds an iOS CarouselView UITest for issue #35675.
  • The PR fix tracks a pending _gotoPosition and suppresses intermediate SetPosition callbacks during programmatic ScrollToItem, matching the described synchronous callback loop when IsScrollAnimated=false.
  • Prior MauiBot review comments warned that _gotoPosition can survive lifecycle/source replacement paths and that the _gotoPosition == -1 guard drops newer programmatic scroll requests while an older target is pending.
  • gh is unauthenticated in this environment, so authenticated review/check surfaces could not be queried; public GitHub API was used for PR/issue/comments where possible.

Code Review Summary

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

Key code review findings:

  • src/Controls/src/Core/Handlers/Items2/iOS/CarouselViewController2.cs:476 — New scroll requests can be dropped while a previous _gotoPosition is pending; collection reset followed immediately by CurrentItem = "Item 2b" can skip the second scroll because _gotoPosition is still 0.
  • ⚠️ src/Controls/src/Core/Handlers/Items2/iOS/CarouselViewController2.cs — Prior MauiBot warning: _gotoPosition is not reset in teardown/dispose or ItemsSource replacement/empty-source paths, so stale state can suppress valid positions after reattach/source changes.
  • ⚠️ src/Controls/src/Core/Handlers/Items2/iOS/CarouselViewController2.cs:476 — Prior MauiBot warning: the pending-target guard ignores newer requested targets instead of replacing the pending target.

Fix Candidates

# Source Approach Test Result Files Changed Notes
PR PR #35848 Add _gotoPosition state to suppress intermediate scroll callbacks and clear it when the target callback arrives ✅ PASSED (Gate) CarouselViewController2.cs, Issue35675.cs tests Original PR; gate result supplied by caller, but code review found stale/dropped-target risks

🔬 Code Review — Deep Analysis

Code Review — PR #35848

Independent Assessment

What this changes: Adds _gotoPosition state in iOS/MacCatalyst CarouselViewController2 to suppress intermediate native SetPosition callbacks while programmatically scrolling, plus an iOS UI regression test for issue 35675.
Inferred motivation: Avoid a feedback loop/freeze when ItemsSource changes and CurrentItem is set with IsScrollAnimated=false.

Reconciliation with PR Narrative

Author claims: PR metadata access through gh is unavailable in this environment; public API access was attempted separately for pre-flight context.
Agreement/disagreement: Local diff matches an attempted fix for iOS CarouselView scroll/position callback loops.

Prior Review Reconciliation

Could not query authenticated top-level reviews, inline comments, or issue comments because gh auth status reports no GitHub authentication. Prior ❌ Error findings are therefore unknown.

Blast Radius Assessment

  • Runs for all instances: Yes — all iOS/MacCatalyst CarouselView programmatic scrolls go through this path.
  • Startup impact: No.
  • Static/shared state: No; _gotoPosition is per controller.

CI Status

  • Required-check result: unavailable
  • Classification: undetermined due to missing gh authentication
  • Action taken: confidence capped low; no GitHub comments posted.

Findings

❌ Error — New scroll requests can be dropped while a previous _gotoPosition is pending

src/Controls/src/Core/Handlers/Items2/iOS/CarouselViewController2.cs:476

ScrollToPosition now only scrolls when _gotoPosition == -1. If a collection update sets _gotoPosition for a forced scroll, and app code then immediately sets CurrentItem/Position to another item before UIKit reports the first target, the second request is ignored. This can leave native position and CarouselView.CurrentItem out of sync, and can even let the stale callback overwrite the app’s intended item.

This appears to affect the added test scenario itself: after ItemsSource reset, CollectionViewUpdated calls ScrollToPosition(0, 0, false, true) and sets _gotoPosition = 0; then setting CurrentItem = "Item 2b" calls UpdateFromCurrentItem, but ScrollToPosition(2, 0, false) is skipped because _gotoPosition is still 0.

Failure-Mode Probing

  • New app-driven target while old scroll pending: skipped by _gotoPosition == -1 gate.
  • ScrollToItem(..., animate:false) emits no later position callback: _gotoPosition can remain stale and block future scrolls.
  • Collection update plus immediate CurrentItem set: likely still reproduces stale/incorrect item selection.

Verdict: NEEDS_CHANGES

Confidence: low
Summary: The fix introduces per-instance suppression state in platform UI plumbing, but it is not replaceable/cancelable for newer programmatic scroll requests. CI and prior reviews could not be verified due missing gh authentication.


🛠️ Fix — Analysis & Comparison

Fix Candidates

# Source Approach Test Result Files Changed Notes
1 try-fix-1 Reentrancy guard around ScrollToItem plus replaceable _pendingScrollTarget for newer requests ✅ PASS 1 file Passed CV2DoesNotFreezeWhenSettingCurrentItemWithIsScrollAnimatedFalse; self-review clean. Different from PR because it suppresses synchronous re-entry only while ScrollToItem is executing and never blocks newer target requests.
PR PR #35848 _gotoPosition pending-target state suppresses SetPosition callbacks until the target position arrives ✅ PASSED (Gate) 3 files Original PR; gate result supplied by caller. Code review found dropped newer-target and stale lifecycle-state risks.

Candidate Details

try-fix-1 — Reentrancy Guard with Replaceable Target

Approach: Use _isScrollingToPosition to suppress synchronous UIKit callbacks while a non-animated ScrollToItem call is executing. If another scroll request arrives during that synchronous call, store it in _pendingScrollTarget and execute it immediately after the current ScrollToItem returns.

Why it is different from the PR fix: The PR tracks a target position in _gotoPosition and blocks all new ScrollToPosition calls while that target is pending. Candidate 1 treats the bug as a reentrancy problem instead: it suppresses only the synchronous native callback window and makes the pending target replaceable, so immediate CurrentItem/Position updates are not dropped.

Diff: CustomAgentLogsTmp/PRState/35848/PRAgent/try-fix/attempt-1/fix.diff

Test results: Pass — iOS UI test CV2DoesNotFreezeWhenSettingCurrentItemWithIsScrollAnimatedFalse passed (1/1, 891ms).

Failure analysis: Not applicable; candidate passed. The useful lesson from code review was that any alternative must allow newer programmatic targets to replace/cancel older pending scroll state.

Cross-Pollination

Model Round New Ideas? Details
claude-opus-4.6 1 Yes Generated and tested Candidate 1: reentrancy guard plus replaceable pending target.
claude-opus-4.7 2 Not run Stopped early because Candidate 1 passed all requested tests and is demonstrably better than the PR fix for the reviewed failure mode.
gpt-5.3-codex 2 Not run Stopped early because Candidate 1 passed all requested tests and is demonstrably better than the PR fix for the reviewed failure mode.
gpt-5.5 2 Not run Stopped early because Candidate 1 passed all requested tests and is demonstrably better than the PR fix for the reviewed failure mode.

Exhausted: No — stopped by success criterion.
Selected Fix: Candidate #1 — It passed the iOS regression test and directly fixes the code-review concern in the PR by making newer scroll targets replaceable instead of dropped, while keeping state scoped to the synchronous ScrollToItem reentrancy window.


📝 Recommended PR Title & Description

Assessment: ✏️ Recommend updating — the current metadata accurately describes the submitted _gotoPosition PR fix, but the winning fix replaces that approach with transient reentrancy suppression and a replaceable pending target.

Recommended title

[iOS/MacCatalyst] CarouselView2: Fix freeze when IsScrollAnimated is false

Recommended description

### Issue Details
- CarouselView2 (CV2) on iOS freezes with an infinite loop when ItemsSource is swapped and CurrentItem is set programmatically with IsScrollAnimated=False — the app becomes completely unresponsive.

### Root Cause
- When IsScrollAnimated=False, UICollectionView.ScrollToItem(animated:false) fires scroll callbacks synchronously, causing CarouselView2 scroll/position logic to re-enter itself and loop indefinitely.

### Description of Change
- Added transient reentrancy tracking in CarouselViewController2 so scroll-driven SetPosition callbacks are suppressed only while a programmatic ScrollToItem call is executing.
- Added a replaceable pending scroll target so newer programmatic Position/CurrentItem requests made during that synchronous re-entry window are not dropped; the latest requested target runs immediately after the current ScrollToItem call returns.
- Cleared pending scroll state when the collection is rebuilt so stale targets do not survive ItemsSource updates.

### Key Technical Details
- Uses _isScrollingToPosition to identify the synchronous UIKit callback window.
- Uses _pendingScrollTarget to preserve the newest requested target if another scroll request arrives during ScrollToItem.
- Avoids treating pending state as a long-lived busy latch, which prevents stale lifecycle/source replacement state from suppressing future scrolls.

### Issues Fixed
Fixes #35675

### Validated the behaviour in the following platforms

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

### Output
| Before | After |
|----------|----------|
| <video src="https://github.com/user-attachments/assets/00a9844d-354f-4b95-b0e2-47243e1e0cc6"> | <video src="https://github.com/user-attachments/assets/b9c9bca2-79a0-43e6-9a34-b625c0f175c3"> |

🏁 Report — Final Recommendation

Comparative Fix Report — PR #35848

Candidates compared

Candidate Approach Regression result Review result Rank
try-fix-1 Suppress synchronous UIKit re-entry only while inside ScrollToItem, with a replaceable pending target for newer requests ✅ PASS Clean self-review; addresses PR reviewer concerns 1
pr-plus-reviewer PR intent plus expert feedback, replacing the non-replaceable _gotoPosition latch with transient reentrancy/pending-target handling Not separately re-run Conceptually sound but redundant with try-fix-1 2
pr _gotoPosition pending target suppresses intermediate position updates until the target callback arrives ✅ PASSED gate Major risks: stale lifecycle state and dropped newer scroll requests 3

Analysis

The raw PR fix correctly identifies that UICollectionView.ScrollToItem(animated:false) can synchronously fire scroll callbacks and re-enter CarouselView2 position logic. The supplied gate passed: the regression test fails without the fix and passes with the PR fix. However, the implementation stores _gotoPosition as persistent controller state and uses _gotoPosition == -1 as a busy latch. That creates two important correctness risks: pending state can survive source/lifecycle transitions if the expected callback does not arrive, and newer programmatic scroll requests are ignored while an older target is pending.

pr-plus-reviewer applies the expert feedback by making the pending target replaceable and scoping suppression to the synchronous ScrollToItem re-entry window. That fixes the reviewer's actionable concerns, but it converges on the same implementation strategy as try-fix-1.

try-fix-1 is the best candidate because it passed the iOS regression test and directly addresses the bug's root cause without the PR's stale-state and dropped-target failure modes. It uses transient _isScrollingToPosition state around ScrollToItem, suppresses synchronous SetPosition callbacks only during that call, and lets any newer target requested during re-entry replace the old one and run immediately afterward.

Winning candidate

Winner: try-fix-1

Rationale: try-fix-1 is the only candidate that is both regression-tested and free of the expert reviewer's major correctness concerns. The raw PR fix passes the narrow gate but remains riskier because its _gotoPosition latch can persist or drop newer scroll requests.


🧭 Next Steps — alternative fix proposed (try-fix-1)

Automated review — alternative fix proposed

The expert-reviewer evaluation compared the PR fix against automatically generated candidates and selected try-fix-1 as the strongest fix.

Why: try-fix-1 passed the iOS regression test and fixes the synchronous ScrollToItem re-entry without the PR fix's stale _gotoPosition state or dropped newer-target risk.

Please consider applying the candidate diff below (or use it as guidance). Once you push an update, this workflow will re-trigger and re-evaluate.

Candidate diff (try-fix-1)
diff --git a/src/Controls/src/Core/Handlers/Items2/iOS/CarouselViewController2.cs b/src/Controls/src/Core/Handlers/Items2/iOS/CarouselViewController2.cs
index 7736815047..502eba95f0 100644
--- a/src/Controls/src/Core/Handlers/Items2/iOS/CarouselViewController2.cs
+++ b/src/Controls/src/Core/Handlers/Items2/iOS/CarouselViewController2.cs
@@ -19,6 +19,8 @@ namespace Microsoft.Maui.Controls.Handlers.Items2
 		bool _isInternalCollectionUpdate = false;
 		int _section = 0;
 		bool _wasDetachedFromWindow = false;
+		bool _isScrollingToPosition = false;
+		int _pendingScrollTarget = -1;
 		CarouselViewLoopManager _carouselViewLoopManager;
 		CancellationTokenSource _scrollDebounce;
 
@@ -326,6 +328,10 @@ namespace Microsoft.Maui.Controls.Handlers.Items2
 			// Clear before anything else so SetPosition/SetCurrentItem called from this method are not suppressed
 			_isInternalCollectionUpdate = false;
 
+			// Collection was rebuilt — any pending scroll target is now stale
+			_pendingScrollTarget = -1;
+			_isScrollingToPosition = false;
+
 			int targetPosition;
 			if (_positionAfterUpdate == -1)
 			{
@@ -333,8 +339,6 @@ namespace Microsoft.Maui.Controls.Handlers.Items2
 				return;
 			}
 
-			//_gotoPosition = -1;
-
 			// We need to update the position while modifying the collection.
 			targetPosition = GetTargetPosition();
 
@@ -474,6 +478,14 @@ namespace Microsoft.Maui.Controls.Handlers.Items2
 
 			if (goToPosition != carouselPosition || forceScroll)
 			{
+				// If we're already inside a ScrollToItem call (synchronous re-entry from UIKit),
+				// record the newer target so it can be executed after the current scroll completes.
+				if (_isScrollingToPosition)
+				{
+					_pendingScrollTarget = goToPosition;
+					return;
+				}
+
 				UICollectionViewScrollPosition uICollectionViewScrollPosition = IsHorizontal ? UICollectionViewScrollPosition.CenteredHorizontally : UICollectionViewScrollPosition.CenteredVertically;
 				var goToIndexPath = GetScrollToIndexPath(goToPosition);
 
@@ -482,7 +494,20 @@ namespace Microsoft.Maui.Controls.Handlers.Items2
 					return;
 				}
 
+				_isScrollingToPosition = true;
+				_pendingScrollTarget = -1;
 				CollectionView.ScrollToItem(goToIndexPath, uICollectionViewScrollPosition, animate);
+				_isScrollingToPosition = false;
+
+				// If a newer scroll target was requested during the ScrollToItem call
+				// (e.g., collection reset triggered SetPosition(0), then CurrentItem set to item 2),
+				// execute it now.
+				if (_pendingScrollTarget != -1)
+				{
+					var nextTarget = _pendingScrollTarget;
+					_pendingScrollTarget = -1;
+					ScrollToPosition(nextTarget, goToPosition, animate, true);
+				}
 			}
 		}
 
@@ -494,6 +519,12 @@ namespace Microsoft.Maui.Controls.Handlers.Items2
 				return;
 			}
 
+			// Suppress synchronous UIKit scroll callbacks during a programmatic ScrollToItem call
+			if (_isScrollingToPosition)
+			{
+				return;
+			}
+
 			if (ItemsView is not CarouselView carousel)
 			{
 				return;

PureWeen pushed a commit that referenced this pull request Jun 22, 2026
…rollAnimated=False (#35848)

<!-- 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
- CarouselView2 (CV2) on iOS freezes with an infinite loop when
ItemsSource is swapped and CurrentItem is set programmatically with
IsScrollAnimated=False — the app becomes completely unresponsive.

### Root Cause
- When IsScrollAnimated=False,
UICollectionView.ScrollToItem(animated:false) fires scroll callbacks
synchronously, causing the scroll logic to re-enter itself indefinitely
and making the app completely unresponsive.

### Description of Change
- Added a _gotoPosition field to CarouselViewController2 to track the
intended scroll target and suppress intermediate position updates during
scrolls, preventing infinite loops when IsScrollAnimated is false.

- **Reference** =>
[SetPosition](https://github.com/dotnet/maui/blob/dd5b6d2ee7832952d1b65ba683ba22f8c6220b17/src/Controls/src/Core/Handlers/Items/iOS/CarouselViewController.cs#L516-L534)
(CarouselViewController)
-  Additionally added the missing _gotoPosition cleanup paths:

- Clear _gotoPosition in CollectionViewUpdated when the collection
changes.
   - Guard ScrollToPosition to skip if a scroll is already in-flight.
- Clear _gotoPosition in UpdateFromCurrentItem when the animated scroll
lands at the intended position.


### Issues Fixed
Fixes #35675

### Validated the behaviour in the following platforms

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

### Output
| Before | After |
|----------|----------|
| <video
src="https://github.com/user-attachments/assets/00a9844d-354f-4b95-b0e2-47243e1e0cc6">
| <video
src="https://github.com/user-attachments/assets/b9c9bca2-79a0-43e6-9a34-b625c0f175c3">
|
kubaflo pushed a commit that referenced this pull request Jun 25, 2026
…rollAnimated=False (#35848)

<!-- 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
- CarouselView2 (CV2) on iOS freezes with an infinite loop when
ItemsSource is swapped and CurrentItem is set programmatically with
IsScrollAnimated=False — the app becomes completely unresponsive.

### Root Cause
- When IsScrollAnimated=False,
UICollectionView.ScrollToItem(animated:false) fires scroll callbacks
synchronously, causing the scroll logic to re-enter itself indefinitely
and making the app completely unresponsive.

### Description of Change
- Added a _gotoPosition field to CarouselViewController2 to track the
intended scroll target and suppress intermediate position updates during
scrolls, preventing infinite loops when IsScrollAnimated is false.

- **Reference** =>
[SetPosition](https://github.com/dotnet/maui/blob/dd5b6d2ee7832952d1b65ba683ba22f8c6220b17/src/Controls/src/Core/Handlers/Items/iOS/CarouselViewController.cs#L516-L534)
(CarouselViewController)
-  Additionally added the missing _gotoPosition cleanup paths:

- Clear _gotoPosition in CollectionViewUpdated when the collection
changes.
   - Guard ScrollToPosition to skip if a scroll is already in-flight.
- Clear _gotoPosition in UpdateFromCurrentItem when the animated scroll
lands at the intended position.


### Issues Fixed
Fixes #35675

### Validated the behaviour in the following platforms

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

### Output
| Before | After |
|----------|----------|
| <video
src="https://github.com/user-attachments/assets/00a9844d-354f-4b95-b0e2-47243e1e0cc6">
| <video
src="https://github.com/user-attachments/assets/b9c9bca2-79a0-43e6-9a34-b625c0f175c3">
|
kubaflo pushed a commit that referenced this pull request Jul 3, 2026
…rollAnimated=False (#35848)

<!-- 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
- CarouselView2 (CV2) on iOS freezes with an infinite loop when
ItemsSource is swapped and CurrentItem is set programmatically with
IsScrollAnimated=False — the app becomes completely unresponsive.

### Root Cause
- When IsScrollAnimated=False,
UICollectionView.ScrollToItem(animated:false) fires scroll callbacks
synchronously, causing the scroll logic to re-enter itself indefinitely
and making the app completely unresponsive.

### Description of Change
- Added a _gotoPosition field to CarouselViewController2 to track the
intended scroll target and suppress intermediate position updates during
scrolls, preventing infinite loops when IsScrollAnimated is false.

- **Reference** =>
[SetPosition](https://github.com/dotnet/maui/blob/dd5b6d2ee7832952d1b65ba683ba22f8c6220b17/src/Controls/src/Core/Handlers/Items/iOS/CarouselViewController.cs#L516-L534)
(CarouselViewController)
-  Additionally added the missing _gotoPosition cleanup paths:

- Clear _gotoPosition in CollectionViewUpdated when the collection
changes.
   - Guard ScrollToPosition to skip if a scroll is already in-flight.
- Clear _gotoPosition in UpdateFromCurrentItem when the animated scroll
lands at the intended position.


### Issues Fixed
Fixes #35675

### Validated the behaviour in the following platforms

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

### Output
| Before | After |
|----------|----------|
| <video
src="https://github.com/user-attachments/assets/00a9844d-354f-4b95-b0e2-47243e1e0cc6">
| <video
src="https://github.com/user-attachments/assets/b9c9bca2-79a0-43e6-9a34-b625c0f175c3">
|
@kubaflo kubaflo mentioned this pull request Jul 6, 2026
kubaflo pushed a commit that referenced this pull request Jul 6, 2026
…rollAnimated=False (#35848)

<!-- 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
- CarouselView2 (CV2) on iOS freezes with an infinite loop when
ItemsSource is swapped and CurrentItem is set programmatically with
IsScrollAnimated=False — the app becomes completely unresponsive.

### Root Cause
- When IsScrollAnimated=False,
UICollectionView.ScrollToItem(animated:false) fires scroll callbacks
synchronously, causing the scroll logic to re-enter itself indefinitely
and making the app completely unresponsive.

### Description of Change
- Added a _gotoPosition field to CarouselViewController2 to track the
intended scroll target and suppress intermediate position updates during
scrolls, preventing infinite loops when IsScrollAnimated is false.

- **Reference** =>
[SetPosition](https://github.com/dotnet/maui/blob/dd5b6d2ee7832952d1b65ba683ba22f8c6220b17/src/Controls/src/Core/Handlers/Items/iOS/CarouselViewController.cs#L516-L534)
(CarouselViewController)
-  Additionally added the missing _gotoPosition cleanup paths:

- Clear _gotoPosition in CollectionViewUpdated when the collection
changes.
   - Guard ScrollToPosition to skip if a scroll is already in-flight.
- Clear _gotoPosition in UpdateFromCurrentItem when the animated scroll
lands at the intended position.


### Issues Fixed
Fixes #35675

### Validated the behaviour in the following platforms

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

### Output
| Before | After |
|----------|----------|
| <video
src="https://github.com/user-attachments/assets/00a9844d-354f-4b95-b0e2-47243e1e0cc6">
| <video
src="https://github.com/user-attachments/assets/b9c9bca2-79a0-43e6-9a34-b625c0f175c3">
|
PureWeen pushed a commit that referenced this pull request Jul 7, 2026
…rollAnimated=False (#35848)

<!-- 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
- CarouselView2 (CV2) on iOS freezes with an infinite loop when
ItemsSource is swapped and CurrentItem is set programmatically with
IsScrollAnimated=False — the app becomes completely unresponsive.

### Root Cause
- When IsScrollAnimated=False,
UICollectionView.ScrollToItem(animated:false) fires scroll callbacks
synchronously, causing the scroll logic to re-enter itself indefinitely
and making the app completely unresponsive.

### Description of Change
- Added a _gotoPosition field to CarouselViewController2 to track the
intended scroll target and suppress intermediate position updates during
scrolls, preventing infinite loops when IsScrollAnimated is false.

- **Reference** =>
[SetPosition](https://github.com/dotnet/maui/blob/dd5b6d2ee7832952d1b65ba683ba22f8c6220b17/src/Controls/src/Core/Handlers/Items/iOS/CarouselViewController.cs#L516-L534)
(CarouselViewController)
-  Additionally added the missing _gotoPosition cleanup paths:

- Clear _gotoPosition in CollectionViewUpdated when the collection
changes.
   - Guard ScrollToPosition to skip if a scroll is already in-flight.
- Clear _gotoPosition in UpdateFromCurrentItem when the animated scroll
lands at the intended position.


### Issues Fixed
Fixes #35675

### Validated the behaviour in the following platforms

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

### Output
| Before | After |
|----------|----------|
| <video
src="https://github.com/user-attachments/assets/00a9844d-354f-4b95-b0e2-47243e1e0cc6">
| <video
src="https://github.com/user-attachments/assets/b9c9bca2-79a0-43e6-9a34-b625c0f175c3">
|
PureWeen pushed a commit that referenced this pull request Jul 7, 2026
…rollAnimated=False (#35848)

<!-- 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
- CarouselView2 (CV2) on iOS freezes with an infinite loop when
ItemsSource is swapped and CurrentItem is set programmatically with
IsScrollAnimated=False — the app becomes completely unresponsive.

### Root Cause
- When IsScrollAnimated=False,
UICollectionView.ScrollToItem(animated:false) fires scroll callbacks
synchronously, causing the scroll logic to re-enter itself indefinitely
and making the app completely unresponsive.

### Description of Change
- Added a _gotoPosition field to CarouselViewController2 to track the
intended scroll target and suppress intermediate position updates during
scrolls, preventing infinite loops when IsScrollAnimated is false.

- **Reference** =>
[SetPosition](https://github.com/dotnet/maui/blob/dd5b6d2ee7832952d1b65ba683ba22f8c6220b17/src/Controls/src/Core/Handlers/Items/iOS/CarouselViewController.cs#L516-L534)
(CarouselViewController)
-  Additionally added the missing _gotoPosition cleanup paths:

- Clear _gotoPosition in CollectionViewUpdated when the collection
changes.
   - Guard ScrollToPosition to skip if a scroll is already in-flight.
- Clear _gotoPosition in UpdateFromCurrentItem when the animated scroll
lands at the intended position.


### Issues Fixed
Fixes #35675

### Validated the behaviour in the following platforms

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

### Output
| Before | After |
|----------|----------|
| <video
src="https://github.com/user-attachments/assets/00a9844d-354f-4b95-b0e2-47243e1e0cc6">
| <video
src="https://github.com/user-attachments/assets/b9c9bca2-79a0-43e6-9a34-b625c0f175c3">
|
kubaflo pushed a commit that referenced this pull request Jul 10, 2026
…rollAnimated=False (#35848)

<!-- 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
- CarouselView2 (CV2) on iOS freezes with an infinite loop when
ItemsSource is swapped and CurrentItem is set programmatically with
IsScrollAnimated=False — the app becomes completely unresponsive.

### Root Cause
- When IsScrollAnimated=False,
UICollectionView.ScrollToItem(animated:false) fires scroll callbacks
synchronously, causing the scroll logic to re-enter itself indefinitely
and making the app completely unresponsive.

### Description of Change
- Added a _gotoPosition field to CarouselViewController2 to track the
intended scroll target and suppress intermediate position updates during
scrolls, preventing infinite loops when IsScrollAnimated is false.

- **Reference** =>
[SetPosition](https://github.com/dotnet/maui/blob/dd5b6d2ee7832952d1b65ba683ba22f8c6220b17/src/Controls/src/Core/Handlers/Items/iOS/CarouselViewController.cs#L516-L534)
(CarouselViewController)
-  Additionally added the missing _gotoPosition cleanup paths:

- Clear _gotoPosition in CollectionViewUpdated when the collection
changes.
   - Guard ScrollToPosition to skip if a scroll is already in-flight.
- Clear _gotoPosition in UpdateFromCurrentItem when the animated scroll
lands at the intended position.


### Issues Fixed
Fixes #35675

### Validated the behaviour in the following platforms

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

### Output
| Before | After |
|----------|----------|
| <video
src="https://github.com/user-attachments/assets/00a9844d-354f-4b95-b0e2-47243e1e0cc6">
| <video
src="https://github.com/user-attachments/assets/b9c9bca2-79a0-43e6-9a34-b625c0f175c3">
|
kubaflo pushed a commit that referenced this pull request Jul 15, 2026
…rollAnimated=False (#35848)

<!-- 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
- CarouselView2 (CV2) on iOS freezes with an infinite loop when
ItemsSource is swapped and CurrentItem is set programmatically with
IsScrollAnimated=False — the app becomes completely unresponsive.

### Root Cause
- When IsScrollAnimated=False,
UICollectionView.ScrollToItem(animated:false) fires scroll callbacks
synchronously, causing the scroll logic to re-enter itself indefinitely
and making the app completely unresponsive.

### Description of Change
- Added a _gotoPosition field to CarouselViewController2 to track the
intended scroll target and suppress intermediate position updates during
scrolls, preventing infinite loops when IsScrollAnimated is false.

- **Reference** =>
[SetPosition](https://github.com/dotnet/maui/blob/dd5b6d2ee7832952d1b65ba683ba22f8c6220b17/src/Controls/src/Core/Handlers/Items/iOS/CarouselViewController.cs#L516-L534)
(CarouselViewController)
-  Additionally added the missing _gotoPosition cleanup paths:

- Clear _gotoPosition in CollectionViewUpdated when the collection
changes.
   - Guard ScrollToPosition to skip if a scroll is already in-flight.
- Clear _gotoPosition in UpdateFromCurrentItem when the animated scroll
lands at the intended position.


### Issues Fixed
Fixes #35675

### Validated the behaviour in the following platforms

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

### Output
| Before | After |
|----------|----------|
| <video
src="https://github.com/user-attachments/assets/00a9844d-354f-4b95-b0e2-47243e1e0cc6">
| <video
src="https://github.com/user-attachments/assets/b9c9bca2-79a0-43e6-9a34-b625c0f175c3">
|
kubaflo pushed a commit that referenced this pull request Jul 22, 2026
…rollAnimated=False (#35848)

<!-- 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
- CarouselView2 (CV2) on iOS freezes with an infinite loop when
ItemsSource is swapped and CurrentItem is set programmatically with
IsScrollAnimated=False — the app becomes completely unresponsive.

### Root Cause
- When IsScrollAnimated=False,
UICollectionView.ScrollToItem(animated:false) fires scroll callbacks
synchronously, causing the scroll logic to re-enter itself indefinitely
and making the app completely unresponsive.

### Description of Change
- Added a _gotoPosition field to CarouselViewController2 to track the
intended scroll target and suppress intermediate position updates during
scrolls, preventing infinite loops when IsScrollAnimated is false.

- **Reference** =>
[SetPosition](https://github.com/dotnet/maui/blob/dd5b6d2ee7832952d1b65ba683ba22f8c6220b17/src/Controls/src/Core/Handlers/Items/iOS/CarouselViewController.cs#L516-L534)
(CarouselViewController)
-  Additionally added the missing _gotoPosition cleanup paths:

- Clear _gotoPosition in CollectionViewUpdated when the collection
changes.
   - Guard ScrollToPosition to skip if a scroll is already in-flight.
- Clear _gotoPosition in UpdateFromCurrentItem when the animated scroll
lands at the intended position.


### Issues Fixed
Fixes #35675

### Validated the behaviour in the following platforms

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

### Output
| Before | After |
|----------|----------|
| <video
src="https://github.com/user-attachments/assets/00a9844d-354f-4b95-b0e2-47243e1e0cc6">
| <video
src="https://github.com/user-attachments/assets/b9c9bca2-79a0-43e6-9a34-b625c0f175c3">
|
@github-actions github-actions Bot locked and limited conversation to collaborators Jul 23, 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 collectionview-cv2 community ✨ Community Contribution partner/syncfusion Issues / PR's with Syncfusion collaboration platform/ios s/agent-fix-win AI found a better alternative fix than the PR 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.

Screen frozen when using CarouselView with IsScrollAnimated = False

5 participants