Repository navigation
Fix #7536: crash when changing source during SelectionChanged - #22102
Merged
Merged
Conversation
Reproduces the "Cannot change source while update is in progress" crash that occurs when a SelectingItemsControl's ItemsSource is changed from within its own SelectionChanged handler while the selection is being lost. When selection is lost, CommitOperation bumps the operation UpdateCount before raising LostSelection but never decrements it, so SelectionChanged is raised with UpdateCount > 0 and SetSource throws. Claude-Session: https://claude.ai/code/session_01FXP1ejZ9VhUwecY9QCRKVb Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
When the selection was lost, SelectionModel.CommitOperation incremented the operation's UpdateCount before raising LostSelection but never decremented it. As a result the rest of the commit - including the SelectionChanged event - ran with UpdateCount > 0, so a handler that changed the control's source (as StructuredLogViewer's UpdateBreadcrumb does) hit the "Cannot change source while update is in progress." guard in SetSource and threw. Decrement UpdateCount again once the LostSelection handler has returned so that the batching only covers the handler itself and the SelectionChanged event is free to change the source. Claude-Session: https://claude.ai/code/session_01FXP1ejZ9VhUwecY9QCRKVb Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…cted reselects Covers the interaction between the #7536 fix and AlwaysSelected: clearing the selection makes AlwaysSelected reselect the first item via LostSelection (which must still fold into the current operation), and a SelectionChanged handler that then changes the selection must be honoured rather than swallowed by the batch update wrapping the LostSelection handler. Fails before the fix (selection stays on the reselected item), passes after. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FXP1ejZ9VhUwecY9QCRKVb
|
You can test this PR using the following package version. |
MrJul
reviewed
Aug 31, 2026
MrJul
left a comment
Member
There was a problem hiding this comment.
I think Copilot's comment on the test is valid.
Aside from that, this looks good.
I'm a bit surprised the absence of a matching decrement didn't cause more issues. Since the operation is quickly disposed, I guess the problem was fairly contained.
Member
Author
|
@MrJul test updated. |
|
You can test this PR using the following package version. |
MrJul
pushed a commit
to MrJul/Avalonia
that referenced
this pull request
Sep 2, 2026
…ed (AvaloniaUI#22102) * Add failing test for AvaloniaUI#7536 Reproduces the "Cannot change source while update is in progress" crash that occurs when a SelectingItemsControl's ItemsSource is changed from within its own SelectionChanged handler while the selection is being lost. When selection is lost, CommitOperation bumps the operation UpdateCount before raising LostSelection but never decrements it, so SelectionChanged is raised with UpdateCount > 0 and SetSource throws. Claude-Session: https://claude.ai/code/session_01FXP1ejZ9VhUwecY9QCRKVb Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Fix AvaloniaUI#7536: crash when changing source during SelectionChanged When the selection was lost, SelectionModel.CommitOperation incremented the operation's UpdateCount before raising LostSelection but never decremented it. As a result the rest of the commit - including the SelectionChanged event - ran with UpdateCount > 0, so a handler that changed the control's source (as StructuredLogViewer's UpdateBreadcrumb does) hit the "Cannot change source while update is in progress." guard in SetSource and threw. Decrement UpdateCount again once the LostSelection handler has returned so that the batching only covers the handler itself and the SelectionChanged event is free to change the source. Claude-Session: https://claude.ai/code/session_01FXP1ejZ9VhUwecY9QCRKVb Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Add test for changing selection from SelectionChanged when AlwaysSelected reselects Covers the interaction between the AvaloniaUI#7536 fix and AlwaysSelected: clearing the selection makes AlwaysSelected reselect the first item via LostSelection (which must still fold into the current operation), and a SelectionChanged handler that then changes the selection must be honoured rather than swallowed by the batch update wrapping the LostSelection handler. Fails before the fix (selection stays on the reselected item), passes after. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FXP1ejZ9VhUwecY9QCRKVb * Assert that `SelectionChanged` was called. --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Fixes #7536: an
InvalidOperationException("Cannot change source while update is in progress.") when aSelectingItemsControl's source is changed from within its ownSelectionChangedhandler while the selection is being lost.Cause
In
SelectionModel.CommitOperation, when the selection is lost the code bumps the operation'sUpdateCountbefore raisingLostSelectionso that any selection change made by theLostSelectionhandler (e.g.AlwaysSelectedre-selecting the first item) folds into the current operation. However it never decremented the count again, so the rest of the commit — including theSelectionChangedevent — ran withUpdateCount > 0.As a result:
SelectionChangedhandler that changed the control's source (as StructuredLogViewer'sUpdateBreadcrumbdoes) hit theUpdateCount > 0guard inSetSourceand threw.SelectionChangedhandler that changed the selection had its change batched into the outer operation and then silently discarded when the commit finished.Note the non-lost-selection path already ran
SelectionChangedatUpdateCount == 0; this only brings the lost-selection path in line with it.Fix
Decrement
UpdateCountagain once theLostSelectionhandler returns, so the batching only wraps that handler and the subsequentSelectionChangedevent runs atUpdateCount == 0.Tests
Changing_ItemsSource_During_SelectionChanged_When_Selection_Lost_Does_Not_Throw— reproduces the original crash.Can_Change_Selection_From_SelectionChanged_When_AlwaysSelected_Reselects— pins the interaction withAlwaysSelected: the re-selection still folds into the operation, and an in-handler selection change is now honoured instead of being swallowed. Both fail before the fix and pass after.Full
SelectingItemsControlTests*(540),SelectionModelTests*(122),ListBoxTestsandTreeViewTestssuites pass.🤖 Generated with Claude Code