Skip to content

Fix ListBox crash when scrolling after item removal - #21838

Merged
MrJul merged 2 commits into
AvaloniaUI:mainfrom
NathanDrake2406:nathan/fix-20085-listbox-invalid-arrange
Jul 24, 2026
Merged

Fix ListBox crash when scrolling after item removal#21838
MrJul merged 2 commits into
AvaloniaUI:mainfrom
NathanDrake2406:nathan/fix-20085-listbox-invalid-arrange

Conversation

@NathanDrake2406

Copy link
Copy Markdown
Contributor

What does the pull request do?

Prevents VirtualizingStackPanel from arranging realized containers at a NaN position while ScrollIntoView is waiting for a viewport update. This fixes the deterministic ListBox crash reported in #20085.

What is the current behavior?

After scrolling a virtualized ListBox to its end, removing an item before the realized range marks that range's stored start position as unstable. Calling ScrollIntoView(0) then intentionally defers measure until the effective viewport changes, but the intervening arrange consumes the unstable NaN position and throws InvalidOperationException: Invalid Arrange rectangle.

What is the updated/expected behavior with this PR?

The transitional arrange uses the panel's existing element-position estimator when the realized range has an unstable start position. Once the viewport update arrives, the normal measure pass replaces the estimate with the exact position. The list can scroll back to the new first item without throwing.

Validation on macOS ARM64 with .NET 10:

  • Added Removing_First_Item_After_Scrolling_To_End_Should_Allow_Scrolling_To_Start, which reproduced the exception before the fix and verifies the new first item after scrolling.
  • Ran ListBoxVirtualizationIssueTests: 6 passed, 0 failed.
  • Ran VirtualizingStackPanelTests: 130 passed, 0 failed.
  • Ran the full Avalonia.Controls.UnitTests executable: 3,648 passed, 1 existing intentional skip, 0 failed.

How was the solution implemented (if it's not obvious)?

RealizedStackElements.StartU deliberately returns NaN when collection changes make the cached position unreliable. ArrangeOverride now recognizes that sentinel and obtains a finite transitional position through GetOrEstimateElementU, the same estimator already used when positioning unrealized and focused elements.

The commits follow the repository's bug-fix convention: the first commit adds the failing behavioral test, and the second commit contains the fix.

Checklist

Breaking changes

None. The change only replaces an invalid transitional arrange coordinate with the panel's existing estimate.

Obsoletions / Deprecations

None.

Fixed issues

Fixes #20085

@NathanDrake2406
NathanDrake2406 marked this pull request as ready for review July 23, 2026 16:27
@avaloniaui-bot

Copy link
Copy Markdown

You can test this PR using the following package version. 12.2.999-cibuild0067667-alpha. (feed url: https://nuget-feed-all.avaloniaui.net/v3/index.json) [PRBUILDID]

@MrJul MrJul added bug backport-candidate-12.1.x Consider this PR for backporting to 12.1 branch labels Jul 24, 2026

@MrJul MrJul left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM!

@MrJul
MrJul added this pull request to the merge queue Jul 24, 2026
Merged via the queue into AvaloniaUI:main with commit 4fc9848 Jul 24, 2026
11 checks passed
MrJul pushed a commit that referenced this pull request Jul 29, 2026
* Add regression test for ListBox removal scroll crash

* Fix virtualized arrange after collection changes
@MrJul MrJul added backported-12.1.x and removed backport-candidate-12.1.x Consider this PR for backporting to 12.1 branch labels Jul 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

"Invalid Arrange rectangle" when deleting an item from a ListBox and then scrolling

3 participants