-
-
Notifications
You must be signed in to change notification settings - Fork 2.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix SelectedItemsControl initialization property order #13800
Fix SelectedItemsControl initialization property order #13800
Conversation
You can test this PR using the following package version. |
What is the situation, when the user binds the whole SelectingItemsControl.Selection in XAML? |
Yes, binding the Let me add a few tests to confirm and fix that. |
@MrJul this looked good to me, and not sure that binding Given that is it ready for merge or not? |
Adding backport label, as it seems to be safe to backport. |
075e569
to
96c7869
Compare
Sorry for the late response!
The warning is still here on Even without setting anything, getting |
Added one last commit, fixing |
You can test this PR using the following package version. |
* Add SelectingItemsControl property init order tests * Property order in SelectedItemsControl doesn't matter on init * Fix SelectedItemsControl properties during init when Selection is set * Fixed SelectedItemsControl.AnchorIndex after init
What does the pull request do?
This PR ensures the order of selection-related properties in
SelectedItemsControl
doesn't matter when set in XAML.These properties are
ItemsSource
,SelectedItem
,SelectedIndex
,SelectedValue
andSelectedValueBinding
.What is the current behavior?
Behavior may differ depending on the order the properties are declared in XAML, especially when
ItemsSource
isn't set first.What is the updated/expected behavior with this PR?
The order doesn't matter.
How was the solution implemented (if it's not obvious)?
Sorry, this will be a bit long, as the bug was quite hard to understand in its entirety.
UpdateState
andISelectionModel
As I wrote in #13522 (comment), the selection properties are already guarded by
ISupportInitialize
(BeginInit
/EndInit
, called automatically by the XAML compiler). During this initialization phase, selection properties are stored in a temporaryUpdateState
object, to be applied later to the realISelectionModel
onEndInit
.The
UpdateState
works fine, but the real selection model (Selection
property) shouldn't be accessed during this time. Initializing the selection model will result in various properties being set, as well as hooking up some event handlers. Those handlers may in turn change other properties. Stir a little more andISelectionModel
andUpdateState
will start to fight against each other for the selection throne.The
SelectionModel
is very easy to initialize without realizing it: accessing any selection-related property getter will do, unless the property has already been set in UpdateState.The most common case observed is with
SelectedValue
:SelectedValue
is set normally in XAML.SelectedIndex
was set previously.SelectedIndex
initializesSelection
.EndInit
,Selection
will have itsSource
updated.SelectedValue
to null.(It took me longer than expected to get the whole flow, especially when inspecting values in the debugger was triggering the buggy path.)
This PR avoids initializing
Selection
as long as there's anUpdateState
.SelectedIndex
,SelectedItem
andAnchorIndex
can fall back to-1
,null
and-1
respectively when there's no selection model yet.SelectedItems
probably still have a bug, but it's rarer to have this property bound at the same time as the other selection properties. I'll tackle this in another PR later.SelectedIndex
andSelectedItem
Before this PR, when both
SelectedIndex
andSelectedItem
were set at initialization time (i.e. in XAML), the last one won, erasing the other. To make that deterministic instead, I've implemented a very simple tie breaker: the "non-empty" one (SelectedIndex >= 0
,SelectedItem != null
) wins.I believe this should match most users expectations: bind both
SelectedIndex
andSelectedItem
, set only one in the VM at init time, and watch the other correctly update instead of clearing the selection.(If both are non-empty,
SelectedIndex
is declared winner arbitrarily.)Tests
A bunch of permutation tests have been added, setting the five selection-related properties in all possible orders (120 tests).
Each set of permutations is tested against setting a bound
SelectedItem
,SelectedIndex
orSelectedValue
, ensuring they all result in the exact same selection state (so 360 tests in total).Fixed issues