Fix Picker selection when SelectedItem is removed from ItemsSource#34299
Fix Picker selection when SelectedItem is removed from ItemsSource#34299jpd21122012 wants to merge 9 commits into
Conversation
|
🚀 Dogfood this PR with:
curl -fsSL https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.sh | bash -s -- 34299Or
iex "& { $(irm https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.ps1) } 34299" |
|
Hey there @@jpd21122012! Thank you so much for your PR! Someone from the team will get assigned to your PR shortly and we'll get it reviewed. |
|
Hi, just checking if this PR could be reviewed for the upcoming 10.6 servicing release. This fix ensures that Picker selection is updated correctly when the current SelectedItem is removed from the ItemsSource, preventing stale or inconsistent selection state. The change is minimal and scoped to selection state handling, without affecting public APIs, so it should be safe for servicing. Let me know if any additional scenarios should be validated 👍 |
|
I'm pretty sure this PR will regress some other aspects of the picker |
|
/azp run maui-pr-uitests |
|
Azure Pipelines successfully started running 1 pipeline(s). |
|
/azp run maui-pr-devicetests |
|
Azure Pipelines successfully started running 1 pipeline(s). |
- Avoid modifying shared GetSelectedIndex behavior - Update selection only during collection mutations (add/remove/reset) - Ensure SelectedIndex is reset when SelectedItem is no longer present - Prevent stale or incorrect selection after ItemsSource changes
Thanks for the feedback! I’ve reworked the fix to avoid modifying the shared GetSelectedIndex logic. Instead, the selection is now updated only during collection mutations (add/remove/reset). This ensures that when the selected item is removed from the ItemsSource, the Picker does not fall back to a stale index, while keeping existing selection behavior intact for other scenarios. I also verified this against multiple cases (item removal, insertions, reordering, and binding scenarios) to ensure no regressions. Let me know if you’d like me to add test coverage for this |
There was a problem hiding this comment.
Pull request overview
Fixes Picker selection consistency when ItemsSource mutates so selection is based on the selected object identity (and cleared when the selected object is removed), rather than accidentally “sticking” to an index that now points at a different item.
Changes:
- Introduces
GetSelectedIndexForCollectionMutation()to compute selection index fromSelectedItemwithout falling back to the previousSelectedIndexwhen the item is missing. - Updates
AddItems,RemoveItems, andResetItemsto use the new selection computation for collection-change scenarios. - Explicitly clears selection (
ClampSelectedIndex(-1)) when a removal causesSelectedItemto no longer exist in the backing collection.
- Verify selection is cleared when selected item is removed - Verify selection is preserved when non-selected items are removed - Verify selection remains consistent during insert and reorder scenarios
kubaflo
left a comment
There was a problem hiding this comment.
TestItemsSourceCollectionChangedRemoveAtEndSelected is failing
Selection should be cleared when the selected item is removed from the ItemsSource. Updated test to expect SelectedIndex = -1 and SelectedItem = null.
I investigated the failure in The test was asserting that after removing the selected item from the I updated the test to reflect the correct behavior:
After correcting the expectation, the tests pass. |
|
/azp run maui-pr-uitests , maui-pr-devicetests |
|
Azure Pipelines successfully started running 2 pipeline(s). |
|
/azp run maui-pr-uitests , maui-pr-devicetests |
|
Azure Pipelines successfully started running 2 pipeline(s). |
Corrected logic for detecting removed selected items in Picker, refined index clamping conditions, and ensured the handler is notified to update the Items property after collection changes.
|
/review -b feature/refactor-copilot-yml |
MauiBot
left a comment
There was a problem hiding this comment.
Expert Review — 1 findings
See inline comments for details.
| bool selectedItemWasRemoved = | ||
| SelectedItem != null && | ||
| e.OldItems != null && | ||
| e.OldItems.Cast<object>().Contains(SelectedItem); |
There was a problem hiding this comment.
[major] Logic and Correctness — This treats the selection as removed whenever OldItems contains an equal value, even if an equal selected value still remains in ItemsSource after the mutation. MAUI already uses ItemsSource.IndexOf(SelectedItem) equality semantics for selection, so a collection like ["A", "B", "B"] with SelectedItem == "B" will clear selection when either "B" is removed, despite GetSelectedIndexForCollectionMutation() finding the remaining "B". Please base the clear decision on whether the selected item can still be found after the mutation (for example index == -1) rather than on OldItems.Contains(SelectedItem), and add a duplicate/equality-equivalent regression test.
|
/review -b feature/refactor-copilot-yml |
MauiBot
left a comment
There was a problem hiding this comment.
Expert Review — 1 findings
See inline comments for details.
kubaflo
left a comment
There was a problem hiding this comment.
Could you please check the ai's suggestions?
Update Picker collection mutation handling to preserve selection when an equal/duplicate item still exists in the ItemsSource after removal. Add regression tests covering duplicate selected items and collection mutation scenarios.
Good catch — the previous logic incorrectly relied on I updated the logic to base the clear decision on the resolved post-mutation selected index instead ( I also added a regression test covering duplicate selected items:
and validated the full related regression suite locally:
All tests are now passing successfully. |
|
/review -b feature/refactor-copilot-yml |
MauiBot
left a comment
There was a problem hiding this comment.
Expert Review — 1 findings
See inline comments for details.
🤖 AI Summary
📊 Review Session —
|
| Test | Without Fix (expect FAIL) | With Fix (expect PASS) |
|---|---|---|
🧪 PickerTests PickerTests |
✅ FAIL — 91s | ✅ PASS — 74s |
🔴 Without fix — 🧪 PickerTests: FAIL ✅ · 91s
Determining projects to restore...
Restored /home/vsts/work/1/s/src/TestUtils/src/TestUtils/TestUtils.csproj (in 1.59 sec).
Restored /home/vsts/work/1/s/src/Controls/tests/Core.UnitTests/Controls.Core.UnitTests.csproj (in 1.53 sec).
8 of 10 projects are up-to-date for restore.
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14198555
Graphics -> /home/vsts/work/1/s/artifacts/bin/Graphics/Debug/net10.0/Microsoft.Maui.Graphics.dll
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14198555
Essentials -> /home/vsts/work/1/s/artifacts/bin/Essentials/Debug/net10.0/Microsoft.Maui.Essentials.dll
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14198555
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.80-ci+azdo.14198555
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14198555
Maps -> /home/vsts/work/1/s/artifacts/bin/Maps/Debug/net10.0/Microsoft.Maui.Maps.dll
Controls.Core -> /home/vsts/work/1/s/artifacts/bin/Controls.Core/Debug/net10.0/Microsoft.Maui.Controls.dll
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14198555
Controls.Xaml -> /home/vsts/work/1/s/artifacts/bin/Controls.Xaml/Debug/net10.0/Microsoft.Maui.Controls.Xaml.dll
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14198555
Controls.Maps -> /home/vsts/work/1/s/artifacts/bin/Controls.Maps/Debug/net10.0/Microsoft.Maui.Controls.Maps.dll
TestUtils -> /home/vsts/work/1/s/artifacts/bin/TestUtils/Debug/netstandard2.0/Microsoft.Maui.TestUtils.dll
Controls.Core.UnitTests -> /home/vsts/work/1/s/artifacts/bin/Controls.Core.UnitTests/Debug/net10.0/Microsoft.Maui.Controls.Core.UnitTests.dll
Test run for /home/vsts/work/1/s/artifacts/bin/Controls.Core.UnitTests/Debug/net10.0/Microsoft.Maui.Controls.Core.UnitTests.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.
[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: Microsoft.Maui.Controls.Core.UnitTests
[xUnit.net 00:00:01.10] Discovered: Microsoft.Maui.Controls.Core.UnitTests
[xUnit.net 00:00:01.11] Starting: Microsoft.Maui.Controls.Core.UnitTests
Passed PickerRetainsSelectionWhenUnselectedItemIsRemovedFromItemsSource [15 ms]
Passed NullItemReturnsEmptyStringFromInterface [1 ms]
Passed TestItemsSourceCollectionChangedInsertBeforeSelected(insertionIndex: 0, insertNames: ["George", "Pete"]) [10 ms]
Passed TestItemsSourceCollectionChangedInsertBeforeSelected(insertionIndex: 2, insertNames: ["George"]) [< 1 ms]
Passed TestItemsSourceCollectionChangedInsertBeforeSelected(insertionIndex: 1, insertNames: ["George"]) [< 1 ms]
Passed TestItemsSourceCollectionChangedInsertBeforeSelected(insertionIndex: 1, insertNames: ["George", "Pete"]) [< 1 ms]
Passed TestItemsSourceCollectionChangedInsertBeforeSelected(insertionIndex: 2, insertNames: ["George", "Pete"]) [< 1 ms]
Passed TestItemsSourceCollectionChangedInsertBeforeSelected(insertionIndex: 3, insertNames: ["George"]) [< 1 ms]
Passed TestItemsSourceCollectionChangedInsertBeforeSelected(insertionIndex: 0, insertNames: ["George"]) [< 1 ms]
Passed TestItemsSourceCollectionChangedInsertBeforeSelected(insertionIndex: 3, insertNames: ["George", "Pete"]) [< 1 ms]
Passed TestSelectedIndexAssignedItemsSourceCollectionChangedInsert [2 ms]
Passed TestItemsSourceCollectionChangedReAssign [6 ms]
Passed TestItemsSourceCollectionOfStrings [< 1 ms]
Passed PickerRetainsSelectionAfterInsertReorderingItemsSource [< 1 ms]
Passed TestItemsSourceCollectionChangedRemoveBeforeSelected(removeIndex: 1, removeCount: 2, selectedItemPreserved: False) [4 ms]
Passed TestItemsSourceCollectionChangedRemoveBeforeSelected(removeIndex: 2, removeCount: 1, selectedItemPreserved: True) [< 1 ms]
Passed TestItemsSourceCollectionChangedRemoveBeforeSelected(removeIndex: 0, removeCount: 2, selectedItemPreserved: False) [< 1 ms]
Passed TestItemsSourceCollectionChangedRemoveBeforeSelected(removeIndex: 1, removeCount: 1, selectedItemPreserved: False) [< 1 ms]
[xUnit.net 00:00:01.25] Assert.Equal() Failure: Values differ
[xUnit.net 00:00:01.25] Expected: -1
[xUnit.net 00:00:01.25] Actual: 1
[xUnit.net 00:00:01.25] Stack Trace:
[xUnit.net 00:00:01.26] /_/src/Controls/tests/Core.UnitTests/PickerTests.cs(876,0): at Microsoft.Maui.Controls.Core.UnitTests.PickerTests.PickerClearsSelectionWhenSelectedItemIsRemovedFromItemsSource()
[xUnit.net 00:00:01.26] at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
[xUnit.net 00:00:01.26] at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)
Passed TestItemsSourceCollectionChangedRemoveBeforeSelected(removeIndex: 0, removeCount: 1, selectedItemPreserved: True) [< 1 ms]
Passed TestItemsSourceCollectionChangedRemoveBeforeSelected(removeIndex: 2, removeCount: 2, selectedItemPreserved: True) [< 1 ms]
Passed TestSelectedIndexChangedOnCollectionShrink [1 ms]
Passed TestSelectedIndexOutOfRangeUpdatesSelectedItem [< 1 ms]
Passed TestDisplayConverter [1 ms]
Passed PickerPreservesSelectedItemAfterRemovingItemBeforeSelection [< 1 ms]
Passed TestSelectedIndexInRange [< 1 ms]
Failed PickerClearsSelectionWhenSelectedItemIsRemovedFromItemsSource [2 ms]
Error Message:
Assert.Equal() Failure: Values differ
Expected: -1
Actual: 1
Stack Trace:
at Microsoft.Maui.Controls.Core.UnitTests.PickerTests.PickerClearsSelectionWhenSelectedItemIsRemovedFromItemsSource() in /_/src/Controls/tests/Core.UnitTests/PickerTests.cs:line 876
at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)
Passed TestSelectedItemSet [3 ms]
[xUnit.net 00:00:01.25] PickerClearsSelectionWhenSelectedItemIsRemovedFromItemsSource [FAIL]
[xUnit.net 00:00:01.26] TestItemsSourceCollectionChangedRemoveAtEndSelected(removeCount: 2) [FAIL]
[xUnit.net 00:00:01.26] TestItemsSourceCollectionChangedRemoveAtEndSelected(removeCount: 1) [FAIL]
[xUnit.net 00:00:01.26] Assert.Equal() Failure: Values differ
[xUnit.net 00:00:01.26] Expected: -1
[xUnit.net 00:00:01.26] Actual: 1
[xUnit.net 00:00:01.26] Stack Trace:
[xUnit.net 00:00:01.26] /_/src/Controls/tests/Core.UnitTests/PickerTests.cs(475,0): at Microsoft.Maui.Controls.Core.UnitTests.PickerTests.TestItemsSourceCollectionChangedRemoveAtEndSelected(Int32 removeCount)
[xUnit.net 00:00:01.26] at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
[xUnit.net 00:00:01.26] at System.Reflection.MethodBaseInvoker.InvokeDirectByRefWithFewArgs(Object obj, Span`1 copyOfArgs, BindingFlags invokeAttr)
[xUnit.net 00:00:01.26] Assert.Equal() Failure: Values differ
[xUnit.net 00:00:01.26] Expected: -1
[xUnit.net 00:00:01.26] Actual: 2
[xUnit.net 00:00:01.26] Stack Trace:
[xUnit.net 00:00:01.26] /_/src/Controls/tests/Core.UnitTests/PickerTests.cs(475,0): at Microsoft.Maui.Controls.Core.UnitTests.PickerTests.TestItemsSourceCollectionChangedRemoveAtEndSelected(Int32 removeCount)
[xUnit.net 00:00:01.26] at InvokeStub_PickerTests.TestItemsSourceCollectionChangedRemoveAtEndSelected(Object, Span`1)
[xUnit.net 00:00:01.26] at System.Reflection.MethodBaseInvoker.InvokeWithOneArg(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
Passed TestSelectedIndexAssignedItemsSourceCollectionChangedReAssign [< 1 ms]
Passed TestSelectedIndexAssignedItemsSourceCollectionChangedClear [2 ms]
Passed TestItemsSourceCollectionChangedClear [< 1 ms]
Passed TestSelectedIndexInRangeDefaultSelectedIndex [< 1 ms]
Failed TestItemsSourceCollectionChangedRemoveAtEndSelected(removeCount: 2) [< 1 ms]
Error Message:
Assert.Equal() Failure: Values differ
Expected: -1
Actual: 1
Stack Trace:
at Microsoft.Maui.Controls.Core.UnitTests.PickerTests.TestItemsSourceCollectionChangedRemoveAtEndSelected(Int32 removeCount) in /_/src/Controls/tests/Core.UnitTests/PickerTests.cs:line 475
at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
at System.Reflection.MethodBaseInvoker.InvokeDirectByRefWithFewArgs(Object obj, Span`1 copyOfArgs, BindingFlags invokeAttr)
Failed TestItemsSourceCollectionChangedRemoveAtEndSelected(removeCount: 1) [< 1 ms]
Error Message:
Assert.Equal() Failure: Values differ
Expected: -1
Actual: 2
Stack Trace:
at Microsoft.Maui.Controls.Core.UnitTests.PickerTests.TestItemsSourceCollectionChangedRemoveAtEndSelected(Int32 removeCount) in /_/src/Controls/tests/Core.UnitTests/PickerTests.cs:line 475
at InvokeStub_PickerTests.TestItemsSourceCollectionChangedRemoveAtEndSelected(Object, Span`1)
at System.Reflection.MethodBaseInvoker.InvokeWithOneArg(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
Passed TestSelectedItemChangeSelectedIndex [< 1 ms]
Passed TestNestedDisplayMemberPathExpression [< 1 ms]
Passed TestSetItemsSourceProperty [< 1 ms]
Passed PickerPreservesSelectedItemAfterInsertingItemBeforeSelection [< 1 ms]
Passed TestItemsSourceCollectionChangedAppend [< 1 ms]
Passed SettingSelectedIndexUpdatesSelectedItem [2 ms]
Passed TestSelectedItemAssignedItemsSourceCollectionChangedRemove [< 1 ms]
Passed ThrowsWhenModifyingItemsIfItemsSourceIsSet [< 1 ms]
Passed TestItemsSourceEnums [4 ms]
Passed TestEmptyCollectionResetItems [< 1 ms]
Passed PickerRetainsSelectionWhenDuplicateSelectedItemIsRemoved [< 1 ms]
Passed TestSetSelectedIndexOnNullRows [< 1 ms]
[xUnit.net 00:00:01.27] Finished: Microsoft.Maui.Controls.Core.UnitTests
Passed TestSelectedIndexAssignedItemsSourceCollectionChangedAppend [< 1 ms]
Passed TestSelectedItemDefault [< 1 ms]
Passed TestItemsSourceCollectionChangedInsert [< 1 ms]
Passed TestUnsubscribeINotifyCollectionChanged [< 1 ms]
Passed TestItemsSourceCollectionChangedRemove [< 1 ms]
Test Run Failed.
Total tests: 50
Passed: 47
Failed: 3
Total time: 1.8805 Seconds
🟢 With fix — 🧪 PickerTests: PASS ✅ · 74s
Determining projects to restore...
All projects are up-to-date for restore.
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14198555
Graphics -> /home/vsts/work/1/s/artifacts/bin/Graphics/Debug/net10.0/Microsoft.Maui.Graphics.dll
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14198555
Essentials -> /home/vsts/work/1/s/artifacts/bin/Essentials/Debug/net10.0/Microsoft.Maui.Essentials.dll
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14198555
Core -> /home/vsts/work/1/s/artifacts/bin/Core/Debug/net10.0/Microsoft.Maui.dll
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14198555
Maps -> /home/vsts/work/1/s/artifacts/bin/Maps/Debug/net10.0/Microsoft.Maui.Maps.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.80-ci+azdo.14198555
Controls.Core -> /home/vsts/work/1/s/artifacts/bin/Controls.Core/Debug/net10.0/Microsoft.Maui.Controls.dll
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14198555
##vso[build.updatebuildnumber]10.0.80-ci+azdo.14198555
Controls.Maps -> /home/vsts/work/1/s/artifacts/bin/Controls.Maps/Debug/net10.0/Microsoft.Maui.Controls.Maps.dll
Controls.Xaml -> /home/vsts/work/1/s/artifacts/bin/Controls.Xaml/Debug/net10.0/Microsoft.Maui.Controls.Xaml.dll
TestUtils -> /home/vsts/work/1/s/artifacts/bin/TestUtils/Debug/netstandard2.0/Microsoft.Maui.TestUtils.dll
Controls.Core.UnitTests -> /home/vsts/work/1/s/artifacts/bin/Controls.Core.UnitTests/Debug/net10.0/Microsoft.Maui.Controls.Core.UnitTests.dll
Test run for /home/vsts/work/1/s/artifacts/bin/Controls.Core.UnitTests/Debug/net10.0/Microsoft.Maui.Controls.Core.UnitTests.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.
[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.35] Discovering: Microsoft.Maui.Controls.Core.UnitTests
[xUnit.net 00:00:03.36] Discovered: Microsoft.Maui.Controls.Core.UnitTests
[xUnit.net 00:00:03.38] Starting: Microsoft.Maui.Controls.Core.UnitTests
Passed PickerRetainsSelectionWhenUnselectedItemIsRemovedFromItemsSource [45 ms]
Passed NullItemReturnsEmptyStringFromInterface [1 ms]
Passed TestItemsSourceCollectionChangedInsertBeforeSelected(insertionIndex: 0, insertNames: ["George", "Pete"]) [21 ms]
Passed TestItemsSourceCollectionChangedInsertBeforeSelected(insertionIndex: 2, insertNames: ["George"]) [< 1 ms]
Passed TestItemsSourceCollectionChangedInsertBeforeSelected(insertionIndex: 1, insertNames: ["George"]) [< 1 ms]
Passed TestItemsSourceCollectionChangedInsertBeforeSelected(insertionIndex: 1, insertNames: ["George", "Pete"]) [< 1 ms]
Passed TestItemsSourceCollectionChangedInsertBeforeSelected(insertionIndex: 2, insertNames: ["George", "Pete"]) [< 1 ms]
Passed TestItemsSourceCollectionChangedInsertBeforeSelected(insertionIndex: 3, insertNames: ["George"]) [< 1 ms]
Passed TestItemsSourceCollectionChangedInsertBeforeSelected(insertionIndex: 0, insertNames: ["George"]) [< 1 ms]
Passed TestItemsSourceCollectionChangedInsertBeforeSelected(insertionIndex: 3, insertNames: ["George", "Pete"]) [< 1 ms]
Passed TestSelectedIndexAssignedItemsSourceCollectionChangedInsert [6 ms]
Passed TestItemsSourceCollectionChangedReAssign [15 ms]
Passed TestItemsSourceCollectionOfStrings [< 1 ms]
Passed PickerRetainsSelectionAfterInsertReorderingItemsSource [< 1 ms]
Passed TestItemsSourceCollectionChangedRemoveBeforeSelected(removeIndex: 1, removeCount: 2, selectedItemPreserved: False) [7 ms]
Passed TestItemsSourceCollectionChangedRemoveBeforeSelected(removeIndex: 2, removeCount: 1, selectedItemPreserved: True) [< 1 ms]
Passed TestItemsSourceCollectionChangedRemoveBeforeSelected(removeIndex: 0, removeCount: 2, selectedItemPreserved: False) [< 1 ms]
Passed TestItemsSourceCollectionChangedRemoveBeforeSelected(removeIndex: 1, removeCount: 1, selectedItemPreserved: False) [< 1 ms]
Passed TestItemsSourceCollectionChangedRemoveBeforeSelected(removeIndex: 0, removeCount: 1, selectedItemPreserved: True) [< 1 ms]
Passed TestItemsSourceCollectionChangedRemoveBeforeSelected(removeIndex: 2, removeCount: 2, selectedItemPreserved: True) [< 1 ms]
Passed TestSelectedIndexChangedOnCollectionShrink [3 ms]
Passed TestSelectedIndexOutOfRangeUpdatesSelectedItem [< 1 ms]
Passed TestDisplayConverter [2 ms]
Passed PickerPreservesSelectedItemAfterRemovingItemBeforeSelection [< 1 ms]
Passed TestSelectedIndexInRange [< 1 ms]
Passed PickerClearsSelectionWhenSelectedItemIsRemovedFromItemsSource [< 1 ms]
Passed TestSelectedItemSet [4 ms]
Passed TestSelectedIndexAssignedItemsSourceCollectionChangedReAssign [1 ms]
Passed TestSelectedIndexAssignedItemsSourceCollectionChangedClear [1 ms]
Passed TestItemsSourceCollectionChangedClear [< 1 ms]
Passed TestSelectedIndexInRangeDefaultSelectedIndex [< 1 ms]
Passed TestItemsSourceCollectionChangedRemoveAtEndSelected(removeCount: 2) [< 1 ms]
Passed TestItemsSourceCollectionChangedRemoveAtEndSelected(removeCount: 1) [< 1 ms]
Passed TestSelectedItemChangeSelectedIndex [< 1 ms]
Passed TestNestedDisplayMemberPathExpression [< 1 ms]
Passed TestSetItemsSourceProperty [1 ms]
Passed PickerPreservesSelectedItemAfterInsertingItemBeforeSelection [1 ms]
Passed TestItemsSourceCollectionChangedAppend [< 1 ms]
Passed SettingSelectedIndexUpdatesSelectedItem [2 ms]
Passed TestSelectedItemAssignedItemsSourceCollectionChangedRemove [< 1 ms]
Passed ThrowsWhenModifyingItemsIfItemsSourceIsSet [< 1 ms]
Passed TestItemsSourceEnums [5 ms]
Passed TestEmptyCollectionResetItems [< 1 ms]
Passed PickerRetainsSelectionWhenDuplicateSelectedItemIsRemoved [< 1 ms]
Passed TestSetSelectedIndexOnNullRows [< 1 ms]
[xUnit.net 00:00:03.64] Finished: Microsoft.Maui.Controls.Core.UnitTests
Passed TestSelectedIndexAssignedItemsSourceCollectionChangedAppend [2 ms]
Passed TestSelectedItemDefault [< 1 ms]
Passed TestItemsSourceCollectionChangedInsert [< 1 ms]
Passed TestUnsubscribeINotifyCollectionChanged [< 1 ms]
Passed TestItemsSourceCollectionChangedRemove [3 ms]
Test Run Successful.
Total tests: 50
Passed: 50
Total time: 4.8002 Seconds
📁 Fix files reverted (2 files)
eng/pipelines/ci-copilot.ymlsrc/Controls/src/Core/Picker/Picker.cs
🧪 UI Tests — Picker
Detected UI test categories: Picker
❌ Deep UI tests — 0 passed, 50 failed across 1 category on platform-pool agent (replaces in-process counts above).
🧪 UI Test Execution Results (deep, platform pool)
| Category | Tests | Snapshot diffs |
|---|---|---|
Picker |
0/50 (50 ❌) | — |
❌ Picker — 50 failed tests
ShouldAppearItemsWhenTappingOnPickerUsingPushModalAsync
OneTimeSetUp: System.TimeoutException : Picker items do not appear when tapping on the picker while using PushModalAsync for navigation
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._IssuesUITest.NavigateToIssue(String issue) in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/_IssuesUITest.cs:line 54
at Microsoft.Maui.TestCases.Tests._Is
...
Picker_SetShadow_VerifyShadow
OneTimeSetUp: System.TimeoutException : Timed out waiting for Go To Test button to appear
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.UtilExtensions.NavigateToGallery(IApp app, String page) in /_/src/Controls/tests/TestCases.Shared.Tests/UtilExtensions.cs:line 37
at Microsoft.Maui.TestCases.Tests._GalleryUITest.FixtureSetup() in /_/src/Controls/
...
VerifyGesturePropagationWithDisabledPicker
OneTimeSetUp: System.TimeoutException : A disabled Picker prevents the parent container's GestureRecognizer from being triggered
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._IssuesUITest.NavigateToIssue(String issue) in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/_IssuesUITest.cs:line 54
at Microsoft.Maui.TestCases.Tests._IssuesUIT
...
PickerCanBeOpenedProgrammatically
OneTimeSetUp: System.TimeoutException : [Android] Picker IsOpen not reset when picker is dismissed
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._IssuesUITest.NavigateToIssue(String issue) in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/_IssuesUITest.cs:line 54
at Microsoft.Maui.TestCases.Tests._IssuesUITest.TryToResetTestState() in /
...
Picker_SetFontSizeAndFontAttributesBold_VerifyFontSizeAndAttributes
OneTimeSetUp: System.TimeoutException : Timed out waiting for Go To Test button to appear
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.UtilExtensions.NavigateToGallery(IApp app, String page) in /_/src/Controls/tests/TestCases.Shared.Tests/UtilExtensions.cs:line 37
at Microsoft.Maui.TestCases.Tests._GalleryUITest.FixtureSetup() in /_/src/Controls/
...
PickerShouldShowSelectedItemHighlight
OneTimeSetUp: System.TimeoutException : [Android] Picker Does Not Show Selected Item Highlight
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._IssuesUITest.NavigateToIssue(String issue) in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/_IssuesUITest.cs:line 54
at Microsoft.Maui.TestCases.Tests._IssuesUITest.TryToResetTestState() in /_/sr
...
Issue2499Test
OneTimeSetUp: System.TimeoutException : Binding Context set to Null in Picker
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._IssuesUITest.NavigateToIssue(String issue) in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/_IssuesUITest.cs:line 54
at Microsoft.Maui.TestCases.Tests._IssuesUITest.TryToResetTestState() in /_/src/Controls/tests/
...
Picker_SetTextColorRed_VerifyTextColor
OneTimeSetUp: System.TimeoutException : Timed out waiting for Go To Test button to appear
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.UtilExtensions.NavigateToGallery(IApp app, String page) in /_/src/Controls/tests/TestCases.Shared.Tests/UtilExtensions.cs:line 37
at Microsoft.Maui.TestCases.Tests._GalleryUITest.FixtureSetup() in /_/src/Controls/
...
Picker_SetFontSizeAndFontFamilyDokdo_VerifyFontSizeAndFontFamily
OneTimeSetUp: System.TimeoutException : Timed out waiting for Go To Test button to appear
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.UtilExtensions.NavigateToGallery(IApp app, String page) in /_/src/Controls/tests/TestCases.Shared.Tests/UtilExtensions.cs:line 37
at Microsoft.Maui.TestCases.Tests._GalleryUITest.FixtureSetup() in /_/src/Controls/
...
FocusAndUnFocusMultipleTimes
OneTimeSetUp: System.TimeoutException : Picker not shown when .Focus() is called
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._IssuesUITest.NavigateToIssue(String issue) in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/_IssuesUITest.cs:line 54
at Microsoft.Maui.TestCases.Tests._IssuesUITest.TryToResetTestState() in /_/src/Controls/tes
...
PickerShouldNotCrashWhenSelectedIndexExceedsItemsSourceCount
OneTimeSetUp: System.TimeoutException : Picker ItemsSource Change Triggers Exception: 'Value Does Not Fall Within the Expected Range
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._IssuesUITest.NavigateToIssue(String issue) in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/_IssuesUITest.cs:line 54
at Microsoft.Maui.TestCases.Tests._Issue
...
Picker_SetVerticalTextAlignmentAndSelectedItem_VerifySelectedItem
OneTimeSetUp: System.TimeoutException : Timed out waiting for Go To Test button to appear
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.UtilExtensions.NavigateToGallery(IApp app, String page) in /_/src/Controls/tests/TestCases.Shared.Tests/UtilExtensions.cs:line 37
at Microsoft.Maui.TestCases.Tests._GalleryUITest.FixtureSetup() in /_/src/Controls/
...
Picker_SetIsEnabledFalse_VerifyPickerDisabled
OneTimeSetUp: System.TimeoutException : Timed out waiting for Go To Test button to appear
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.UtilExtensions.NavigateToGallery(IApp app, String page) in /_/src/Controls/tests/TestCases.Shared.Tests/UtilExtensions.cs:line 37
at Microsoft.Maui.TestCases.Tests._GalleryUITest.FixtureSetup() in /_/src/Controls/
...
PickerShouldDismissWhenClickOnOutside
OneTimeSetUp: System.TimeoutException : iOS Picker dismiss does not work when clicking outside of the Picker
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._IssuesUITest.NavigateToIssue(String issue) in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/_IssuesUITest.cs:line 54
at Microsoft.Maui.TestCases.Tests._IssuesUITest.TryToResetTestSt
...
Issue32984PickerShouldResize
OneTimeSetUp: System.TimeoutException : Picker on resize not working on Windows
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._IssuesUITest.NavigateToIssue(String issue) in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/_IssuesUITest.cs:line 54
at Microsoft.Maui.TestCases.Tests._IssuesUITest.TryToResetTestState() in /_/src/Controls/test
...
PickerOpenedFromConstructor
OneTimeSetUp: System.TimeoutException : Add Open/Close API to picker controls (Picker)
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._IssuesUITest.NavigateToIssue(String issue) in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/_IssuesUITest.cs:line 54
at Microsoft.Maui.TestCases.Tests._IssuesUITest.TryToResetTestState() in /_/src/Contro
...
Issue16737Test
OneTimeSetUp: System.TimeoutException : Title colour on Android Picker, initially appears grey
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._IssuesUITest.NavigateToIssue(String issue) in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/_IssuesUITest.cs:line 54
at Microsoft.Maui.TestCases.Tests._IssuesUITest.TryToResetTestState() in /_/sr
...
Picker_SetSelectedIndex_VerifySelectedIndexAndItem
OneTimeSetUp: System.TimeoutException : Timed out waiting for Go To Test button to appear
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.UtilExtensions.NavigateToGallery(IApp app, String page) in /_/src/Controls/tests/TestCases.Shared.Tests/UtilExtensions.cs:line 37
at Microsoft.Maui.TestCases.Tests._GalleryUITest.FixtureSetup() in /_/src/Controls/
...
Picker_SetFlowDirectionRTL_VerifyFlowDirection
OneTimeSetUp: System.TimeoutException : Timed out waiting for Go To Test button to appear
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.UtilExtensions.NavigateToGallery(IApp app, String page) in /_/src/Controls/tests/TestCases.Shared.Tests/UtilExtensions.cs:line 37
at Microsoft.Maui.TestCases.Tests._GalleryUITest.FixtureSetup() in /_/src/Controls/
...
Picker_SetTitleWithFontAttributeBold_VerifyTitleAndFontAttribute
OneTimeSetUp: System.TimeoutException : Timed out waiting for Go To Test button to appear
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.UtilExtensions.NavigateToGallery(IApp app, String page) in /_/src/Controls/tests/TestCases.Shared.Tests/UtilExtensions.cs:line 37
at Microsoft.Maui.TestCases.Tests._GalleryUITest.FixtureSetup() in /_/src/Controls/
...
Picker_SetIsVisibleFalse_VerifyPickerHidden
OneTimeSetUp: System.TimeoutException : Timed out waiting for Go To Test button to appear
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.UtilExtensions.NavigateToGallery(IApp app, String page) in /_/src/Controls/tests/TestCases.Shared.Tests/UtilExtensions.cs:line 37
at Microsoft.Maui.TestCases.Tests._GalleryUITest.FixtureSetup() in /_/src/Controls/
...
Picker_SetCharacterSpacingAndTitle_VerifyBoth
OneTimeSetUp: System.TimeoutException : Timed out waiting for Go To Test button to appear
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.UtilExtensions.NavigateToGallery(IApp app, String page) in /_/src/Controls/tests/TestCases.Shared.Tests/UtilExtensions.cs:line 37
at Microsoft.Maui.TestCases.Tests._GalleryUITest.FixtureSetup() in /_/src/Controls/
...
CorrectItemShouldBeSelectedWhenOpeningPicker
OneTimeSetUp: System.TimeoutException : When opening the Picker, the first item is selected instead of the currently selected item
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._IssuesUITest.NavigateToIssue(String issue) in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/_IssuesUITest.cs:line 54
at Microsoft.Maui.TestCases.Tests._IssuesU
...
Picker_SelectItem_VerifySelectedItem
OneTimeSetUp: System.TimeoutException : Timed out waiting for Go To Test button to appear
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.UtilExtensions.NavigateToGallery(IApp app, String page) in /_/src/Controls/tests/TestCases.Shared.Tests/UtilExtensions.cs:line 37
at Microsoft.Maui.TestCases.Tests._GalleryUITest.FixtureSetup() in /_/src/Controls/
...
BlankScreenOnNavigationBack
OneTimeSetUp: System.TimeoutException : Returning back from navigation to MainPage would result in a blank screen
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._IssuesUITest.NavigateToIssue(String issue) in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/_IssuesUITest.cs:line 54
at Microsoft.Maui.TestCases.Tests._IssuesUITest.TryToResetT
...
CheckNavigationBreaksVisualStatesForPicker
OneTimeSetUp: System.TimeoutException : Navigation breaks VisualState styles for Picker
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._IssuesUITest.NavigateToIssue(String issue) in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/_IssuesUITest.cs:line 54
at Microsoft.Maui.TestCases.Tests._IssuesUITest.TryToResetTestState() in /_/src/Contr
...
PickerShouldNotAllowUserInputThroughKeyboard
OneTimeSetUp: System.TimeoutException : The picker allows you to write text if the keyboard is visible
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._IssuesUITest.NavigateToIssue(String issue) in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/_IssuesUITest.cs:line 54
at Microsoft.Maui.TestCases.Tests._IssuesUITest.TryToResetTestState()
...
Picker_SetTitleColorOrange_VerifyTitleColor
OneTimeSetUp: System.TimeoutException : Timed out waiting for Go To Test button to appear
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.UtilExtensions.NavigateToGallery(IApp app, String page) in /_/src/Controls/tests/TestCases.Shared.Tests/UtilExtensions.cs:line 37
at Microsoft.Maui.TestCases.Tests._GalleryUITest.FixtureSetup() in /_/src/Controls/
...
Picker_SelectedIndexChanged_VerifyEventTriggered
OneTimeSetUp: System.TimeoutException : Timed out waiting for Go To Test button to appear
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.UtilExtensions.NavigateToGallery(IApp app, String page) in /_/src/Controls/tests/TestCases.Shared.Tests/UtilExtensions.cs:line 37
at Microsoft.Maui.TestCases.Tests._GalleryUITest.FixtureSetup() in /_/src/Controls/
...
Picker_SetTitleWithFontSize_VerifyTitleAndFontSize
OneTimeSetUp: System.TimeoutException : Timed out waiting for Go To Test button to appear
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.UtilExtensions.NavigateToGallery(IApp app, String page) in /_/src/Controls/tests/TestCases.Shared.Tests/UtilExtensions.cs:line 37
at Microsoft.Maui.TestCases.Tests._GalleryUITest.FixtureSetup() in /_/src/Controls/
...
(+20 more — see TRX in artifact)
📎 Download drop-deep-uitests artifact (TRX + snapshot diffs)
🔍 Regression Cross-Reference
🔍 Regression Cross-Reference
🟢 No regression risks detected. No labeled bug-fix PRs in the last 6 months touched the modified files.
🔍 Pre-Flight — Context & Validation
Issue: #33307 - The Picker is still binding to the property and reacts to data changes after the page is closed.
PR: #34299 - Fix Picker selection when SelectedItem is removed from ItemsSource
Platforms Affected: Android, Windows
Files Changed: 1 implementation, 1 test
Key Findings
- The issue reproduces when a
Pickerkeeps a stale numericSelectedIndexafter its boundItemsSourcemutates, especially when the selected item is removed or items before it are removed/reordered. - PR Fix Picker selection when SelectedItem is removed from ItemsSource #34299 changes Picker collection-mutation handling to resolve selection by
SelectedItemidentity/equality after the mutation and clear selection when the selected item is no longer present. - Unit tests were added for clearing removed selections, preserving selection after unrelated removals/inserts, and duplicate/equality-equivalent selected values.
- Prior inline review identified an outdated duplicate-value concern that the current PR revision addresses by using the post-mutation lookup result.
- Gate result supplied by caller: tests fail without the fix and pass with the PR fix; gate was not re-run.
Code Review Summary
Verdict: NEEDS_CHANGES
Confidence: high
Errors: 0 | Warnings: 1 | Suggestions: 1
Key code review findings:
⚠️ src/Controls/src/Core/Picker/Picker.cs:RemoveItemsandResetItemscallHandler?.UpdateValue(nameof(IPicker.Items))internally whileCollectionChanged()already calls it unconditionally after the switch, causing redundant handler updates for Remove/Reset.- 💡
src/Controls/src/Core/Picker/Picker.cs:using System.Linq;appears unused.
Fix Candidates
| # | Source | Approach | Test Result | Files Changed | Notes |
|---|---|---|---|---|---|
| PR | PR #34299 | Add mutation-specific selected-index lookup that returns -1 when SelectedItem is absent, use it for add/remove/reset collection changes, and add Picker unit tests. |
✅ PASSED (Gate) | src/Controls/src/Core/Picker/Picker.cs, src/Controls/tests/Core.UnitTests/PickerTests.cs |
Original PR |
🔬 Code Review — Deep Analysis
Code Review — PR #34299
Independent Assessment
What this changes: Introduces a second index-resolution helper GetSelectedIndexForCollectionMutation() that returns -1 when SelectedItem is not found in the collection, instead of the original GetSelectedIndex() fallback to the stale SelectedIndex. Uses this new helper in AddItems, RemoveItems, and ResetItems. Adds an explicit ClampSelectedIndex(-1) branch in RemoveItems when the resolved index is -1, clearing the selection. Also adds Handler?.UpdateValue(nameof(IPicker.Items)) calls inside both RemoveItems and ResetItems.
Inferred motivation: When the selected item was removed from ItemsSource, the old code preserved the numeric SelectedIndex which now pointed to a different item — effectively replacing the user's selection silently. The fix makes the Picker use identity-based selection (track the object, not the slot).
Reconciliation with PR Narrative
Author claims: Previously GetSelectedIndex() returned the stale SelectedIndex when SelectedItem was no longer found, causing incorrect index-based selection after item removal.
Agreement/disagreement: Code confirms the diagnosis. The old GetSelectedIndex() had return newIndex >= 0 ? newIndex : SelectedIndex — the SelectedIndex fallback is exactly the root cause. The new GetSelectedIndexForCollectionMutation() removes that fallback and returns -1 instead. The two-method approach (keeping the old path intact for non-mutation callers) is a safe, minimal change.
Findings
⚠️ Warning — Double Handler?.UpdateValue for Remove and Reset actions
RemoveItems (line ~430) and ResetItems (line ~461) now each call Handler?.UpdateValue(nameof(IPicker.Items)) internally. However, CollectionChanged() (line 383) still calls the same Handler?.UpdateValue(nameof(IPicker.Items)) unconditionally after the switch, meaning every Remove event and every Reset/Move/Replace event now fires the handler mapper twice.
AddItems does NOT have an internal call — it relies solely on the outer one — making the three branches inconsistent.
Calling UpdateValue twice is benign from a correctness standpoint (SetValue/UpdateValue is idempotent), but it fires the platform mapper redundantly. On Windows and iOS this may trigger an unnecessary native ReloadData/Reload or equivalent per mutation. The fix: remove the inner calls from RemoveItems and ResetItems and rely on the existing outer call in CollectionChanged, unless ordering is critical (if it is, remove the outer call for those branches).
Affected lines:
src/Controls/src/Core/Picker/Picker.csline ~430 (insideRemoveItems)src/Controls/src/Core/Picker/Picker.csline ~461 (insideResetItems)
💡 Suggestion — Remove unused using System.Linq;
using System.Linq; was added in this PR (line 9 of the diff) but is not used anywhere in the new or changed code. IList.IndexOf(object) and IList<string>.IndexOf(string) are both available via System.Collections and System.Collections.Generic respectively. Remove the import.
Devil's Advocate
On the double-UpdateValue concern: Could both calls be intentional — e.g., the inner one ensures the handler sees the item list before ClampSelectedIndex fires its SetValue, and the outer one is a belt-and-suspenders guard? Possible, but ClampSelectedIndex calls SetValue(SelectedIndexProperty, ...) which is a separate property path from IPicker.Items, so the ordering of the two UpdateValue(Items) calls relative to each other doesn't change observable behavior. Both map to the same native items-refresh. There's no timing reason to call it twice.
On the two-method approach: Could GetSelectedIndex and GetSelectedIndexForCollectionMutation diverge subtly in the future and cause confusion? Yes — a future maintainer may call the wrong one at a new call site. A brief // Returns -1 when SelectedItem is absent; use during collection mutation comment on GetSelectedIndexForCollectionMutation would mitigate this. The existing review conversation acknowledged this concern; the author chose to keep them separate without adding a comment. Worth noting but not blocking.
On the test PickerRetainsSelectionWhenDuplicateSelectedItemIsRemoved: The duplicate-value scenario (["A","B","B"], remove first "B") is correctly handled: after removal ItemsSource = ["A","B"], and ItemsSource.IndexOf("B") returns 1, so selection is retained. The test is valid.
On changed test TestItemsSourceCollectionChangedRemoveAtEndSelected: The test expectation was updated from "last item stays selected" to "selection cleared" when the selected item at the end is removed. This is the intended new behavior and the change is correct.
CI Status
All 32 check runs completed with success (including maui-pr, all integration tests, and Helix unit tests on Windows in Debug and Release). ✅
Verdict: NEEDS_CHANGES
Confidence: high
Summary: The core fix (identity-based vs. index-based selection on collection mutation) is correct, well-scoped, and has solid unit test coverage. However, RemoveItems and ResetItems now each call Handler?.UpdateValue(nameof(IPicker.Items)) internally and CollectionChanged calls it again unconditionally, causing redundant double-updates for Remove/Reset actions. That inconsistency (AddItems has no inner call) and the potential for unnecessary native redraws should be resolved before merge. The unused using System.Linq; is a minor cleanup. No API surface changes; no thread-safety or handler lifecycle issues observed.
🔧 Fix — Analysis & Comparison
Fix Candidates
| # | Source | Approach | Test Result | Files Changed | Notes |
|---|---|---|---|---|---|
| 1 | try-fix-1 | Inline SelectedItem-aware index resolution directly in collection mutation methods instead of adding a second helper; remove redundant inner Handler?.UpdateValue calls. |
✅ PASS | 1 file | 97/97 Picker unit tests passed. Simpler surface area than PR helper but duplicates the index-resolution expression at multiple call sites, so not selected yet as demonstrably better. |
| 2 | try-fix-2 | Consolidate selected-index lookup into one helper with explicit stale-index fallback semantics (KeepCurrent vs ClearSelection) and use clear-selection fallback during collection mutations. |
✅ PASS | 1 file | 97/97 Picker unit tests passed. Avoids PR's second helper, avoids try-fix-1's repeated inline lookup, removes redundant inner updates, and keeps legacy fallback explicit for existing callers. |
| 3 | try-fix-3 | Move stale-index reconciliation into ClampSelectedIndex through a ReconcileSelectedIndex helper, leaving collection mutation call sites mostly unchanged. |
✅ PASS | 1 file | 97/97 Picker unit tests passed. Meaningfully different, but broader/riskier because it changes all ClampSelectedIndex callers while ItemsSource and SelectedItem are set. |
| 4 | try-fix-4 | Capture the pre-mutation selected item/index in CollectionChanged, mutate the internal item list, then explicitly reconcile selection from the post-mutation ItemsSource. |
✅ PASS | 1 file | 97/97 Picker unit tests passed. Meaningfully different, but more complex and introduces new ResetItems flags/control flow. |
| 5 | try-fix-5 | Use NotifyCollectionChangedEventArgs add/remove/move ranges as the primary algorithm to incrementally adjust SelectedIndex, falling back to selected-item lookup for reset/ambiguous cases. |
❌ FAIL | 2 files | Test run aborted/hung in PickerTests.TestSelectedIndexAssignedItemsSourceCollectionChangedInsert; self-review found a major re-entrant selection regression. |
| PR | PR #34299 | Add GetSelectedIndexForCollectionMutation() helper returning -1 when SelectedItem is absent; use it for add/remove/reset and add Picker regression tests. |
✅ PASSED (Gate) | 2 files | Original PR; gate supplied by caller passed. |
Cross-Pollination
| Model | Round | New Ideas? | Details |
|---|---|---|---|
| claude-opus-4.6 | 1 | Yes | Candidate 1: inline post-mutation selected-item lookup at each mutation call site. |
| claude-opus-4.7 | 1 | Yes | Candidate 2: single helper with explicit fallback policy for stale selected index. |
| gpt-5.3-codex | 1 | Yes | Candidate 3: clamp-path reconciliation via ReconcileSelectedIndex. |
| gpt-5.5 | 1 | Yes | Candidate 4: capture and reconcile selected item after collection mutation. |
| claude-opus-4.6 | 2 | No | No new ideas; attempts cover inline/helper/clamp-time/mutation-time reconciliation, and candidate #2 has the smallest blast radius. |
| claude-opus-4.7 | 2 | No | No new ideas; remaining options are complexity/risk tradeoffs without correctness wins over candidate #2. |
| gpt-5.3-codex | 2 | Yes | Proposed event-args-based incremental index reconciliation; run as candidate #5 and failed due re-entrant selected-index behavior. |
| gpt-5.5 | 2 | No | No new ideas; coercion-pipeline variant would be attempt #3's broader blast radius repackaged. |
Exhausted: Yes
Selected Fix: Candidate #2 — it passes the same regression suite while addressing the code-review concern about split helpers/duplicate semantics more cleanly than the PR, avoiding try-fix-1's repeated inline expression, avoiding try-fix-3's broad clamp-path blast radius, avoiding try-fix-4's extra mutation-control flow, and avoiding try-fix-5's re-entrant selection regression.
📋 Report — Final Recommendation
Comparative Report — PR #34299
Candidates Compared
| Rank | Candidate | Regression result | Assessment |
|---|---|---|---|
| 1 | pr-plus-reviewer |
✅ PASS-equivalent to PR gate; reviewer cleanup is non-behavioral | Best balance. Keeps the PR's targeted, gate-proven fix and regression tests, while applying the expert reviewer's actionable feedback to remove the duplicate RemoveItems() handler update. |
| 2 | try-fix-2 |
✅ PASS — 97/97 Picker tests | Best non-PR alternative. Its single helper with explicit StaleIndexFallback semantics is clean and avoids the PR's second helper, but it is more refactoring than necessary now that expert review found the PR approach sound with only minor cleanup. |
| 3 | pr |
✅ PASS — gate passed | Correct and tested, but ranks below pr-plus-reviewer because it retains the duplicate remove-path handler update flagged by expert review. |
| 4 | try-fix-1 |
✅ PASS — 97/97 Picker tests | Correct and simple, and it removes redundant handler updates, but it duplicates selected-item lookup logic at multiple call sites. |
| 5 | try-fix-4 |
✅ PASS — 97/97 Picker tests | Correct in tests, but more complex: it captures pre-mutation selection and adds ResetItems control-flow flags. The extra coordination is not justified for this fix. |
| 6 | try-fix-3 |
✅ PASS — 97/97 Picker tests | Concise, but broader risk because it changes all ClampSelectedIndex callers when ItemsSource and SelectedItem are set, not just collection mutation paths. |
| 7 | try-fix-5 |
❌ FAIL — regression run aborted/hung | Must rank below all passing candidates. Its event-args incremental reconciliation regressed re-entrant selected-index behavior during add notifications. |
Winner
Winner: pr-plus-reviewer
The raw PR fix is functionally sound and gate-proven: tests fail without it and pass with it. The expert reviewer found no correctness blocker, only a duplicate remove-path handler update. Applying that feedback yields the lowest-risk winning candidate because it preserves the PR's test coverage and targeted behavior while removing the only actionable review finding.
try-fix-2 remains the strongest independent alternative if the team prefers a single parameterized helper over the PR's two-helper design, but that refactor is not required to fix the issue and is not clearly safer than the reviewed PR-plus-cleanup candidate.
Good catch — I’ve removed the extra refresh to keep the remove path aligned with the existing add behavior and avoid duplicate handler update work. The regression suite is still passing successfully, including the duplicate/equality-equivalent item scenario. |
|
/review -b feature/refactor-copilot-yml |
|
/azp run maui-pr-uitests |
|
Azure Pipelines successfully started running 1 pipeline(s). |
Description of Change
Fixes incorrect selection behavior in
Pickerwhen the selected item is removed fromItemsSource.Previously, if the selected item was removed,
Pickerpreserved the previousSelectedIndex, which could result in selecting a different item that now occupies the same index.This caused index-based selection instead of identity-based selection.
Root Cause
GetSelectedIndex()returned the previousSelectedIndexwhenSelectedItemwas no longer found in the collection.This caused the control to keep an index that now pointed to a different item.
Fix
If the
SelectedItemis no longer present in the collection, the control now returns-1, clearing the selection.Verified Scenarios
Fixes #33307