Picker: Refresh ItemDisplayBinding when bound item properties change#29922
Picker: Refresh ItemDisplayBinding when bound item properties change#29922devanathan-vaithiyanathan wants to merge 16 commits into
Conversation
|
/azp run MAUI-UITests-public |
|
Azure Pipelines successfully started running 1 pipeline(s). |
| { | ||
| App.WaitForElement("PickerButton"); | ||
| App.Tap("PickerButton"); | ||
| VerifyScreenshot(); |
|
/azp run MAUI-UITests-public |
|
Azure Pipelines successfully started running 1 pipeline(s). |
|
@jsuarezruiz , pending snapshots has been added. |
|
/azp run MAUI-UITests-public |
|
Azure Pipelines successfully started running 1 pipeline(s). |
|
|
||
| void OnItemsSourceChanged(IList oldValue, IList newValue) | ||
| { | ||
| if (oldValue is not null) |
There was a problem hiding this comment.
This logic is duplicated, can extract it to a method.
There was a problem hiding this comment.
Inside the methods, check items.Count == 0 before iterating to avoid unnecessary loops
6e94f72 to
5961883
Compare
|
🚀 Dogfood this PR with:
curl -fsSL https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.sh | bash -s -- 29922Or
iex "& { $(irm https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.ps1) } 29922" |
There was a problem hiding this comment.
Pull request overview
This PR adds support for automatically refreshing the Picker display when a bound item's property changes through ItemDisplayBinding. The implementation subscribes to PropertyChanged events on items in the ItemsSource and updates the display when the bound property changes.
Key Changes:
- Event subscription for
INotifyPropertyChangeditems in ItemsSource - Automatic refresh when bound property changes
- Dynamic subscription/unsubscription when items are added/removed
- Comprehensive UI tests with screenshot verification for all platforms
Reviewed changes
Copilot reviewed 3 out of 7 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
src/Controls/src/Core/Picker/Picker.cs |
Core implementation: adds PropertyChanged event handling for items, subscription/unsubscription logic in OnItemsSourceChanged and CollectionChanged methods |
src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue25634.cs |
NUnit UI test verifying the picker display updates after property change |
src/Controls/tests/TestCases.HostApp/Issues/Issue25634.cs |
Test HostApp page with Picker, ObservableCollection, and INotifyPropertyChanged model |
src/Controls/tests/TestCases.Android.Tests/snapshots/android/VerifyPickerItemDisplayBindingValue.png |
Android test screenshot baseline |
src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/VerifyPickerItemDisplayBindingValue.png |
iOS test screenshot baseline |
src/Controls/tests/TestCases.WinUI.Tests/snapshots/windows/VerifyPickerItemDisplayBindingValue.png |
Windows test screenshot baseline |
src/Controls/tests/TestCases.Mac.Tests/snapshots/mac/VerifyPickerItemDisplayBindingValue.png |
MacCatalyst test screenshot baseline |
| { | ||
| if (e.PropertyName == binding.Path) | ||
| { | ||
| ResetItems(); |
There was a problem hiding this comment.
Potential performance issue: ResetItems() is called for every property change on any item, even if that item is not currently visible or selected. For large collections where many items change their properties simultaneously, this could cause excessive UI updates.
Consider optimizing to only refresh the display when the selected item's property changes:
void OnPickerItemPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (ItemDisplayBinding is Binding binding && !string.IsNullOrEmpty(binding.Path))
{
if (e.PropertyName == binding.Path)
{
// Only reset if the changed item is the currently selected item
// or if we need to update all items in the dropdown
if (sender == SelectedItem)
{
// Update just the display text for the selected item
Handler?.UpdateValue(nameof(IPicker.SelectedItem));
}
else
{
// For items in the dropdown list, consider a more targeted update
ResetItems();
}
}
}
}| ResetItems(); | |
| // Only reset if the changed item is not the currently selected item | |
| if (sender == SelectedItem) | |
| { | |
| // Update just the display text for the selected item | |
| Handler?.UpdateValue(nameof(IPicker.SelectedItem)); | |
| } | |
| else | |
| { | |
| // For items in the dropdown list, update the items | |
| ResetItems(); | |
| } |
| if (e.PropertyName == binding.Path) | ||
| { | ||
| ResetItems(); | ||
| } | ||
| } |
There was a problem hiding this comment.
The OnPickerItemPropertyChanged method only handles Binding type but not other BindingBase types like TypedBinding or custom binding implementations. This could cause the feature to silently fail for other binding types.
Consider handling all BindingBase types or documenting the limitation:
void OnPickerItemPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (ItemDisplayBinding is Binding binding && !string.IsNullOrEmpty(binding.Path))
{
if (e.PropertyName == binding.Path || string.IsNullOrEmpty(e.PropertyName))
{
ResetItems();
}
}
else if (ItemDisplayBinding is not null && ItemDisplayBinding is not Binding)
{
// For other binding types, refresh on any property change
// since we can't determine the specific path
ResetItems();
}
}Note: Also consider checking for string.IsNullOrEmpty(e.PropertyName) which indicates all properties changed.
| if (e.PropertyName == binding.Path) | |
| { | |
| ResetItems(); | |
| } | |
| } | |
| // For Binding, only reset if the relevant property changed, or all properties changed | |
| if (e.PropertyName == binding.Path || string.IsNullOrEmpty(e.PropertyName)) | |
| { | |
| ResetItems(); | |
| } | |
| } | |
| else if (ItemDisplayBinding is not null && ItemDisplayBinding is not Binding) | |
| { | |
| // For other BindingBase types (TypedBinding, custom), reset on any property change | |
| ResetItems(); | |
| } |
| if (oldValue is not null) | ||
| { | ||
| foreach (var item in oldValue) | ||
| { | ||
| if (item is INotifyPropertyChanged npc) | ||
| { | ||
| npc.PropertyChanged -= OnPickerItemPropertyChanged; | ||
| } | ||
| } | ||
| } | ||
| if (newValue is not null && ItemDisplayBinding is not null) | ||
| { | ||
| foreach (var item in newValue) | ||
| { | ||
| if (item is INotifyPropertyChanged npc) | ||
| { | ||
| npc.PropertyChanged += OnPickerItemPropertyChanged; | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
Missing cleanup when Picker is disposed or removed from the visual tree. The PropertyChanged event handlers attached to items will prevent garbage collection of both the Picker and the items, causing a memory leak.
Consider overriding cleanup methods to unsubscribe from events:
protected override void OnHandlerChanging(HandlerChangingEventArgs args)
{
base.OnHandlerChanging(args);
if (args.NewHandler == null && ItemsSource is not null)
{
// Unsubscribe when being removed from the visual tree
foreach (var item in ItemsSource)
{
if (item is INotifyPropertyChanged npc)
{
npc.PropertyChanged -= OnPickerItemPropertyChanged;
}
}
}
}Alternatively, use weak event patterns to avoid memory leaks.
This comment has been minimized.
This comment has been minimized.
|
/review -b feature/refactor-copilot-yml |
kubaflo
left a comment
There was a problem hiding this comment.
Could you please check the ai's suggestions?
|
/review -b feature/enhanced-reviewer -p ios |
MauiBot
left a comment
There was a problem hiding this comment.
Expert Review — 3 findings
See inline comments for details.
|
|
||
| // Unsubscribe when being removed from visual tree to prevent memory leaks | ||
| if (args.NewHandler == null) | ||
| UnsubscribeFromItemPropertyChanges(ItemsSource); |
There was a problem hiding this comment.
[major] Handler lifecycle - This unsubscribes item PropertyChanged handlers when the picker loses its handler, but there is no matching re-subscribe path when the same picker later gets a new handler. Scenario: a Picker in a Shell tab or virtualized page is detached and reattached; subsequent ItemDisplayBinding property changes no longer refresh the displayed text.
|
|
||
| void CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) | ||
| { | ||
| UnsubscribeFromItemPropertyChanges(e.OldItems); |
There was a problem hiding this comment.
[major] Memory Leak Prevention - NotifyCollectionChangedAction.Reset commonly has OldItems == null, so this leaves all previously subscribed items hooked to OnPickerItemPropertyChanged. After ObservableCollection.Clear() or a reset-style source refresh, removed item view models can still retain the Picker and trigger resets, causing stale callbacks and leaks.
| { | ||
| if (ItemDisplayBinding is Binding binding && !string.IsNullOrEmpty(binding.Path)) | ||
| { | ||
| if (string.IsNullOrEmpty(e.PropertyName) || e.PropertyName == binding.Path) |
There was a problem hiding this comment.
[major] Logic and Correctness - Comparing PropertyChangedEventArgs.PropertyName to the full binding path misses nested-path invalidation. For ItemDisplayBinding = new Binding("Address.Name"), replacing the root Address property raises PropertyChanged("Address"), but this condition ignores it, leaving the picker text stale.
kubaflo
left a comment
There was a problem hiding this comment.
Could you please check the ai's suggestions?
@kubaflo , I have addressed the AI suggestion |
|
/review -b feature/enhanced-reviewer -p ios |
MauiBot
left a comment
There was a problem hiding this comment.
AI Review Summary
@devanathan-vaithiyanathan — new AI review results are available based on this last commit:
41bf371. To request a fresh review after new comments or commits, comment/review rerun.
Review Sessions — click to expand
Gate — Test Before & After Fix
Gate Result: ✅ PASSED
Platform: IOS · Base: main · Merge base: bb4e7040
| Test | Without Fix (expect FAIL) | With Fix (expect PASS) |
|---|---|---|
🖥️ Issue25634 Issue25634 |
✅ FAIL — 334s | ✅ PASS — 125s |
🔴 Without fix — 🖥️ Issue25634: FAIL ✅ · 334s
Determining projects to restore...
Restored /Users/cloudtest/vss/_work/1/s/src/Graphics/src/Graphics/Graphics.csproj (in 662 ms).
Restored /Users/cloudtest/vss/_work/1/s/src/Controls/src/BindingSourceGen/Controls.BindingSourceGen.csproj (in 650 ms).
Restored /Users/cloudtest/vss/_work/1/s/src/Essentials/src/Essentials.csproj (in 5.07 sec).
Restored /Users/cloudtest/vss/_work/1/s/src/Controls/Foldable/src/Controls.Foldable.csproj (in 6.86 sec).
Restored /Users/cloudtest/vss/_work/1/s/src/Controls/src/Core/Controls.Core.csproj (in 6.86 sec).
Restored /Users/cloudtest/vss/_work/1/s/src/Controls/src/Xaml/Controls.Xaml.csproj (in 6.86 sec).
Restored /Users/cloudtest/vss/_work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj (in 6.86 sec).
Restored /Users/cloudtest/vss/_work/1/s/src/Controls/Maps/src/Controls.Maps.csproj (in 6.86 sec).
Restored /Users/cloudtest/vss/_work/1/s/src/BlazorWebView/src/Maui/Microsoft.AspNetCore.Components.WebView.Maui.csproj (in 6.87 sec).
Restored /Users/cloudtest/vss/_work/1/s/src/Core/src/Core.csproj (in 6.89 sec).
Restored /Users/cloudtest/vss/_work/1/s/src/Core/maps/src/Maps.csproj (in 6.2 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.14376859
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.14376859
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.14376859
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.14376859
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.14376859
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.14376859
##vso[build.updatebuildnumber]10.0.90-ci+azdo.14376859
##vso[build.updatebuildnumber]10.0.90-ci+azdo.14376859
Controls.Maps -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.Maps/Debug/net10.0-ios26.0/Microsoft.Maui.Controls.Maps.dll
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
##vso[build.updatebuildnumber]10.0.90-ci+azdo.14376859
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
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:04.17
Determining projects to restore...
Restored /Users/cloudtest/vss/_work/1/s/src/Controls/src/BindingSourceGen/Controls.BindingSourceGen.csproj (in 932 ms).
Restored /Users/cloudtest/vss/_work/1/s/src/Graphics/src/Graphics/Graphics.csproj (in 932 ms).
Restored /Users/cloudtest/vss/_work/1/s/src/TestUtils/src/VisualTestUtils/VisualTestUtils.csproj (in 39 ms).
Restored /Users/cloudtest/vss/_work/1/s/src/TestUtils/src/UITest.Core/UITest.Core.csproj (in 7 ms).
Restored /Users/cloudtest/vss/_work/1/s/src/Controls/tests/CustomAttributes/Controls.CustomAttributes.csproj (in 3 ms).
Restored /Users/cloudtest/vss/_work/1/s/src/Essentials/src/Essentials.csproj (in 81 ms).
Restored /Users/cloudtest/vss/_work/1/s/src/Controls/src/Core/Controls.Core.csproj (in 1.11 sec).
Restored /Users/cloudtest/vss/_work/1/s/src/Core/src/Core.csproj (in 1.13 sec).
Restored /Users/cloudtest/vss/_work/1/s/src/TestUtils/src/UITest.NUnit/UITest.NUnit.csproj (in 1.81 sec).
Restored /Users/cloudtest/vss/_work/1/s/src/TestUtils/src/UITest.Appium/UITest.Appium.csproj (in 3.17 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 6.97 sec).
Restored /Users/cloudtest/vss/_work/1/s/src/Controls/tests/TestCases.iOS.Tests/Controls.TestCases.iOS.Tests.csproj (in 7 sec).
##vso[build.updatebuildnumber]10.0.90-ci+azdo.14376859
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.14376859
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.14376859
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.14376859
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.08] 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/15/2026 4:42:36 AM FixtureSetup for Issue25634(iOS)
>>>>> 6/15/2026 4:42:40 AM VerifyPickerItemDisplayBindingValue Start
>>>>> 6/15/2026 4:42:44 AM VerifyPickerItemDisplayBindingValue Stop
>>>>> 6/15/2026 4:42:44 AM Log types: syslog, crashlog, performance, safariConsole, safariNetwork, server
Failed VerifyPickerItemDisplayBindingValue [3 s]
Error Message:
VisualTestUtils.VisualTestFailedException :
Snapshot different than baseline: VerifyPickerItemDisplayBindingValue.png (1.15% difference)
If the correct baseline has changed (this isn't a a bug), then update the baseline image.
See test attachment or download the build artifacts to get the new snapshot file.
More info: https://aka.ms/visual-test-workflow
Stack Trace:
at VisualTestUtils.VisualRegressionTester.Fail(String message) in /_/src/TestUtils/src/VisualTestUtils/VisualRegressionTester.cs:line 162
at VisualTestUtils.VisualRegressionTester.VerifyMatchesSnapshot(String name, ImageSnapshot actualImage, String environmentName, ITestContext testContext) in /_/src/TestUtils/src/VisualTestUtils/VisualRegressionTester.cs:line 123
at Microsoft.Maui.TestCases.Tests.UITest.<VerifyScreenshot>g__Verify|13_0(String name, <>c__DisplayClass13_0&) in /_/src/Controls/tests/TestCases.Shared.Tests/UITest.cs:line 477
at Microsoft.Maui.TestCases.Tests.UITest.VerifyScreenshot(String name, Nullable`1 retryDelay, Nullable`1 retryTimeout, Int32 cropLeft, Int32 cropRight, Int32 cropTop, Int32 cropBottom, Double tolerance) in /_/src/Controls/tests/TestCases.Shared.Tests/UITest.cs:line 309
at Microsoft.Maui.TestCases.Tests.Issues.Issue25634.VerifyPickerItemDisplayBindingValue() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue25634.cs:line 20
at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)
NUnit Adapter 4.5.0.0: Test execution complete
Results File: /Users/cloudtest/vss/_work/1/s/CustomAgentLogsTmp/UITests/TestResults/Issue25634.trx
Total tests: 1
Failed: 1
Test Run Failed.
Total time: 1.5301 Minutes
>>> TRX_RESULT_FILE: /Users/cloudtest/vss/_work/1/s/CustomAgentLogsTmp/UITests/TestResults/Issue25634.trx
🟢 With fix — 🖥️ Issue25634: PASS ✅ · 125s
Determining projects to restore...
Restored /Users/cloudtest/vss/_work/1/s/src/Controls/src/BindingSourceGen/Controls.BindingSourceGen.csproj (in 427 ms).
Restored /Users/cloudtest/vss/_work/1/s/src/Graphics/src/Graphics/Graphics.csproj (in 449 ms).
Restored /Users/cloudtest/vss/_work/1/s/src/Essentials/src/Essentials.csproj (in 403 ms).
Restored /Users/cloudtest/vss/_work/1/s/src/Controls/src/Core/Controls.Core.csproj (in 500 ms).
Restored /Users/cloudtest/vss/_work/1/s/src/Core/src/Core.csproj (in 517 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.14376859
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.14376859
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.14376859
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.14376859
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.14376859
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.14376859
##vso[build.updatebuildnumber]10.0.90-ci+azdo.14376859
##vso[build.updatebuildnumber]10.0.90-ci+azdo.14376859
##vso[build.updatebuildnumber]10.0.90-ci+azdo.14376859
Controls.Maps -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.Maps/Debug/net10.0-ios26.0/Microsoft.Maui.Controls.Maps.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.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
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:03.44
Determining projects to restore...
Restored /Users/cloudtest/vss/_work/1/s/src/Controls/src/BindingSourceGen/Controls.BindingSourceGen.csproj (in 411 ms).
Restored /Users/cloudtest/vss/_work/1/s/src/Graphics/src/Graphics/Graphics.csproj (in 355 ms).
Restored /Users/cloudtest/vss/_work/1/s/src/Essentials/src/Essentials.csproj (in 421 ms).
Restored /Users/cloudtest/vss/_work/1/s/src/Controls/src/Core/Controls.Core.csproj (in 445 ms).
Restored /Users/cloudtest/vss/_work/1/s/src/Core/src/Core.csproj (in 465 ms).
8 of 13 projects are up-to-date for restore.
##vso[build.updatebuildnumber]10.0.90-ci+azdo.14376859
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.14376859
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.14376859
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.14376859
Controls.Core -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/Controls.Core/Debug/net10.0/Microsoft.Maui.Controls.dll
UITest.Core -> /Users/cloudtest/vss/_work/1/s/artifacts/bin/UITest.Core/Debug/net10.0/UITest.Core.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.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.06] Discovering: Controls.TestCases.iOS.Tests
[xUnit.net 00:00:00.20] 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/15/2026 4:44:44 AM FixtureSetup for Issue25634(iOS)
>>>>> 6/15/2026 4:44:49 AM VerifyPickerItemDisplayBindingValue Start
>>>>> 6/15/2026 4:44:50 AM VerifyPickerItemDisplayBindingValue Stop
Passed VerifyPickerItemDisplayBindingValue [1 s]
NUnit Adapter 4.5.0.0: Test execution complete
Results File: /Users/cloudtest/vss/_work/1/s/CustomAgentLogsTmp/UITests/TestResults/Issue25634.trx
Test Run Successful.
Total tests: 1
Passed: 1
Total time: 25.6668 Seconds
>>> TRX_RESULT_FILE: /Users/cloudtest/vss/_work/1/s/CustomAgentLogsTmp/UITests/TestResults/Issue25634.trx
📁 Fix files reverted (9 files)
eng/pipelines/ci-copilot.ymlsrc/Controls/src/Core/Picker/Picker.cssrc/Controls/src/Core/PublicAPI/net-android/PublicAPI.Unshipped.txtsrc/Controls/src/Core/PublicAPI/net-ios/PublicAPI.Unshipped.txtsrc/Controls/src/Core/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txtsrc/Controls/src/Core/PublicAPI/net-tizen/PublicAPI.Unshipped.txtsrc/Controls/src/Core/PublicAPI/net-windows/PublicAPI.Unshipped.txtsrc/Controls/src/Core/PublicAPI/net/PublicAPI.Unshipped.txtsrc/Controls/src/Core/PublicAPI/netstandard/PublicAPI.Unshipped.txt
UI Tests — Picker
Detected UI test categories: Picker
❌ Deep UI tests — 12 passed, 29 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 |
12/41 (29 ❌) | 23 diff PNGs |
❌ Picker — 29 failed tests
CheckNavigationBreaksVisualStatesForPicker
System.InvalidOperationException :
Snapshot different than baseline: CheckNavigationBreaksVisualStatesForPicker.png (size differs - baseline is 1124x2286 pixels, actual is 1206x2472 pixels)
If the correct baseline has changed (this isn't a a bug), then update the baseline image.
See test attachment or download the build artifacts to get the new snapshot file.
More info: https://aka.ms/visual-test-workflow
iOS 26 visual tests require an iPhone 11 Pro simulator for correct screen resolution.
To create the simulator, run:
xcrun simctl create "iPhone 11 Pro" com.apple.CoreSimulator.SimDeviceType.iPhone-11-Pro com.apple.CoreSimulator.SimRuntime.iOS-26-0
Then run the tests targeting the new simulator.
----> VisualTestUtils.VisualTestFailedException :
Snapshot different than baseline: CheckNavigationBreaksVisualStatesForPicker.png (size differs - baseline is 1124x2286 pixels, actual is 1206x2472 pixels)
If the correct baseline has changed (this isn't a a bug), then update the baseli
...
PickerShouldDismissWhenClickOnOutside
System.InvalidOperationException :
Snapshot different than baseline: PickerShouldDismissWhenClickOnOutside.png (size differs - baseline is 1124x2286 pixels, actual is 1206x2472 pixels)
If the correct baseline has changed (this isn't a a bug), then update the baseline image.
See test attachment or download the build artifacts to get the new snapshot file.
More info: https://aka.ms/visual-test-workflow
iOS 26 visual tests require an iPhone 11 Pro simulator for correct screen resolution.
To create the simulator, run:
xcrun simctl create "iPhone 11 Pro" com.apple.CoreSimulator.SimDeviceType.iPhone-11-Pro com.apple.CoreSimulator.SimRuntime.iOS-26-0
Then run the tests targeting the new simulator.
----> VisualTestUtils.VisualTestFailedException :
Snapshot different than baseline: PickerShouldDismissWhenClickOnOutside.png (size differs - baseline is 1124x2286 pixels, actual is 1206x2472 pixels)
If the correct baseline has changed (this isn't a a bug), then update the baseline image.
...
InvisibleTimepickerShowsDialogOnFocus
System.TimeoutException : Timed out waiting for element...
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.Issue5159.InvisibleTimepickerShowsDialogOnFocus() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/XFIssue/Issue5159.cs:line 34
at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** arguments, ObjectHa
...
PickerShouldRegainTitle
System.InvalidOperationException :
Snapshot different than baseline: PickerShouldRegainTitle.png (size differs - baseline is 1124x2286 pixels, actual is 1206x2472 pixels)
If the correct baseline has changed (this isn't a a bug), then update the baseline image.
See test attachment or download the build artifacts to get the new snapshot file.
More info: https://aka.ms/visual-test-workflow
iOS 26 visual tests require an iPhone 11 Pro simulator for correct screen resolution.
To create the simulator, run:
xcrun simctl create "iPhone 11 Pro" com.apple.CoreSimulator.SimDeviceType.iPhone-11-Pro com.apple.CoreSimulator.SimRuntime.iOS-26-0
Then run the tests targeting the new simulator.
----> VisualTestUtils.VisualTestFailedException :
Snapshot different than baseline: PickerShouldRegainTitle.png (size differs - baseline is 1124x2286 pixels, actual is 1206x2472 pixels)
If the correct baseline has changed (this isn't a a bug), then update the baseline image.
See test attachment or downl
...
Picker_TapPicker_TakeScreenshot
System.InvalidOperationException : Unable to extract difference percentage from exception message.
at Microsoft.Maui.TestCases.Tests.UITest.VerifyScreenshot(String name, Nullable`1 retryDelay, Nullable`1 retryTimeout, Int32 cropLeft, Int32 cropRight, Int32 cropTop, Int32 cropBottom, Double tolerance) in /_/src/Controls/tests/TestCases.Shared.Tests/UITest.cs:line 296
at Microsoft.Maui.TestCases.Tests.PickerFeatureTests.VerifyPickerScreenshot() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/PickerFeatureTests.cs:line 22
at Microsoft.Maui.TestCases.Tests.PickerFeatureTests.Picker_TapPicker_TakeScreenshot() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/PickerFeatureTests.cs:line 42
at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** arguments, ObjectHandleOnStack sig, BOOL isConstructor, ObjectHandleOnStack result)
at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** arguments, ObjectH
...
PickerShouldShowSelectedItemHighlight
System.InvalidOperationException :
Snapshot different than baseline: PickerShouldShowSelectedItemHighlight.png (size differs - baseline is 1124x2286 pixels, actual is 1206x2472 pixels)
If the correct baseline has changed (this isn't a a bug), then update the baseline image.
See test attachment or download the build artifacts to get the new snapshot file.
More info: https://aka.ms/visual-test-workflow
iOS 26 visual tests require an iPhone 11 Pro simulator for correct screen resolution.
To create the simulator, run:
xcrun simctl create "iPhone 11 Pro" com.apple.CoreSimulator.SimDeviceType.iPhone-11-Pro com.apple.CoreSimulator.SimRuntime.iOS-26-0
Then run the tests targeting the new simulator.
----> VisualTestUtils.VisualTestFailedException :
Snapshot different than baseline: PickerShouldShowSelectedItemHighlight.png (size differs - baseline is 1124x2286 pixels, actual is 1206x2472 pixels)
If the correct baseline has changed (this isn't a a bug), then update the baseline image.
...
Picker_SetShadow_VerifyShadow
System.InvalidOperationException : Unable to extract difference percentage from exception message.
at Microsoft.Maui.TestCases.Tests.UITest.VerifyScreenshot(String name, Nullable`1 retryDelay, Nullable`1 retryTimeout, Int32 cropLeft, Int32 cropRight, Int32 cropTop, Int32 cropBottom, Double tolerance) in /_/src/Controls/tests/TestCases.Shared.Tests/UITest.cs:line 296
at Microsoft.Maui.TestCases.Tests.PickerFeatureTests.VerifyPickerScreenshot() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/PickerFeatureTests.cs:line 22
at Microsoft.Maui.TestCases.Tests.PickerFeatureTests.Picker_SetShadow_VerifyShadow() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/PickerFeatureTests.cs:line 365
at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** arguments, ObjectHandleOnStack sig, BOOL isConstructor, ObjectHandleOnStack result)
at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** arguments, ObjectHa
...
Picker_SetTextColorRed_VerifyTextColor
System.InvalidOperationException : Unable to extract difference percentage from exception message.
at Microsoft.Maui.TestCases.Tests.UITest.VerifyScreenshot(String name, Nullable`1 retryDelay, Nullable`1 retryTimeout, Int32 cropLeft, Int32 cropRight, Int32 cropTop, Int32 cropBottom, Double tolerance) in /_/src/Controls/tests/TestCases.Shared.Tests/UITest.cs:line 296
at Microsoft.Maui.TestCases.Tests.PickerFeatureTests.VerifyPickerScreenshot() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/PickerFeatureTests.cs:line 22
at Microsoft.Maui.TestCases.Tests.PickerFeatureTests.Picker_SetTextColorRed_VerifyTextColor() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/PickerFeatureTests.cs:line 384
at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** arguments, ObjectHandleOnStack sig, BOOL isConstructor, ObjectHandleOnStack result)
at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** arguments,
...
Issue1614Test
System.TimeoutException : Timed out waiting for element...
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.Issue1614.TapPicker(String picker) in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/XFIssue/Issue1614.cs:line 36
at Microsoft.Maui.TestCases.Tests.Issues.Issue1614.Issue1614Test() in /_/src/Controls/tests/TestCases.Shared.Tes
...
InvisiblePickerShowsDialogOnFocus
System.TimeoutException : Timed out waiting for element...
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.Issue5159.InvisiblePickerShowsDialogOnFocus() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/XFIssue/Issue5159.cs:line 43
at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** arguments, ObjectHandle
...
Picker_SetHorizontalTextAlignmentAndSelectedItem_VerifySelectedItem
System.InvalidOperationException : Unable to extract difference percentage from exception message.
at Microsoft.Maui.TestCases.Tests.UITest.VerifyScreenshot(String name, Nullable`1 retryDelay, Nullable`1 retryTimeout, Int32 cropLeft, Int32 cropRight, Int32 cropTop, Int32 cropBottom, Double tolerance) in /_/src/Controls/tests/TestCases.Shared.Tests/UITest.cs:line 296
at Microsoft.Maui.TestCases.Tests.PickerFeatureTests.VerifyPickerScreenshot() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/PickerFeatureTests.cs:line 22
at Microsoft.Maui.TestCases.Tests.PickerFeatureTests.Picker_SetHorizontalTextAlignmentAndSelectedItem_VerifySelectedItem() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/PickerFeatureTests.cs:line 291
at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** arguments, ObjectHandleOnStack sig, BOOL isConstructor, ObjectHandleOnStack result)
at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnSt
...
PickerCanBeOpenedProgrammatically
System.NullReferenceException : Object reference not set to an instance of an object.
at UITest.Appium.HelperExtensions.Click(IUIElement element) in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 412
at UITest.Appium.HelperExtensions.<>c__DisplayClass2_0.<Tap>b__0() in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 36
at UITest.Appium.HelperExtensions.<>c__DisplayClass186_0.<RunWithTimeout>b__0() in /_/src/TestUtils/src/UITest.Appium/HelperExtensions.cs:line 3075
at System.Threading.Tasks.Task`1.InnerInvoke()
at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread threadPoolThread, ExecutionContext executionContext, ContextCallback callback, Object state)
--- End of stack trace from previous location ---
at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread threadPoolThread, ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Tas
...
Picker_Validate_VerifyLabels
System.InvalidOperationException : Unable to extract difference percentage from exception message.
at Microsoft.Maui.TestCases.Tests.UITest.VerifyScreenshot(String name, Nullable`1 retryDelay, Nullable`1 retryTimeout, Int32 cropLeft, Int32 cropRight, Int32 cropTop, Int32 cropBottom, Double tolerance) in /_/src/Controls/tests/TestCases.Shared.Tests/UITest.cs:line 296
at Microsoft.Maui.TestCases.Tests.PickerFeatureTests.VerifyPickerScreenshot() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/PickerFeatureTests.cs:line 22
at Microsoft.Maui.TestCases.Tests.PickerFeatureTests.Picker_Validate_VerifyLabels() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/PickerFeatureTests.cs:line 31
at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** arguments, ObjectHandleOnStack sig, BOOL isConstructor, ObjectHandleOnStack result)
at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** arguments, ObjectHand
...
Picker_SetCharacterSpacing_VerifyCharacterSpacingLabel
System.InvalidOperationException : Unable to extract difference percentage from exception message.
at Microsoft.Maui.TestCases.Tests.UITest.VerifyScreenshot(String name, Nullable`1 retryDelay, Nullable`1 retryTimeout, Int32 cropLeft, Int32 cropRight, Int32 cropTop, Int32 cropBottom, Double tolerance) in /_/src/Controls/tests/TestCases.Shared.Tests/UITest.cs:line 296
at Microsoft.Maui.TestCases.Tests.PickerFeatureTests.VerifyPickerScreenshot() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/PickerFeatureTests.cs:line 22
at Microsoft.Maui.TestCases.Tests.PickerFeatureTests.Picker_SetCharacterSpacing_VerifyCharacterSpacingLabel() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/PickerFeatureTests.cs:line 120
at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** arguments, ObjectHandleOnStack sig, BOOL isConstructor, ObjectHandleOnStack result)
at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, V
...
ShouldAppearItemsWhenTappingOnPickerUsingPushModalAsync
System.InvalidOperationException :
Snapshot different than baseline: ShouldAppearItemsWhenTappingOnPickerUsingPushModalAsync.png (size differs - baseline is 1124x2286 pixels, actual is 1206x2472 pixels)
If the correct baseline has changed (this isn't a a bug), then update the baseline image.
See test attachment or download the build artifacts to get the new snapshot file.
More info: https://aka.ms/visual-test-workflow
iOS 26 visual tests require an iPhone 11 Pro simulator for correct screen resolution.
To create the simulator, run:
xcrun simctl create "iPhone 11 Pro" com.apple.CoreSimulator.SimDeviceType.iPhone-11-Pro com.apple.CoreSimulator.SimRuntime.iOS-26-0
Then run the tests targeting the new simulator.
----> VisualTestUtils.VisualTestFailedException :
Snapshot different than baseline: ShouldAppearItemsWhenTappingOnPickerUsingPushModalAsync.png (size differs - baseline is 1124x2286 pixels, actual is 1206x2472 pixels)
If the correct baseline has changed (this isn't a a bu
...
PickerTitleShouldBeRed
System.InvalidOperationException :
Snapshot different than baseline: PickerTitleShouldBeRed.png (size differs - baseline is 1124x2286 pixels, actual is 1206x2472 pixels)
If the correct baseline has changed (this isn't a a bug), then update the baseline image.
See test attachment or download the build artifacts to get the new snapshot file.
More info: https://aka.ms/visual-test-workflow
iOS 26 visual tests require an iPhone 11 Pro simulator for correct screen resolution.
To create the simulator, run:
xcrun simctl create "iPhone 11 Pro" com.apple.CoreSimulator.SimDeviceType.iPhone-11-Pro com.apple.CoreSimulator.SimRuntime.iOS-26-0
Then run the tests targeting the new simulator.
----> VisualTestUtils.VisualTestFailedException :
Snapshot different than baseline: PickerTitleShouldBeRed.png (size differs - baseline is 1124x2286 pixels, actual is 1206x2472 pixels)
If the correct baseline has changed (this isn't a a bug), then update the baseline image.
See test attachment or downloa
...
Picker_SetSelectedItem_VerifySelectedItemLabel
System.InvalidOperationException : Unable to extract difference percentage from exception message.
at Microsoft.Maui.TestCases.Tests.UITest.VerifyScreenshot(String name, Nullable`1 retryDelay, Nullable`1 retryTimeout, Int32 cropLeft, Int32 cropRight, Int32 cropTop, Int32 cropBottom, Double tolerance) in /_/src/Controls/tests/TestCases.Shared.Tests/UITest.cs:line 296
at Microsoft.Maui.TestCases.Tests.PickerFeatureTests.VerifyPickerScreenshot() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/PickerFeatureTests.cs:line 22
at Microsoft.Maui.TestCases.Tests.PickerFeatureTests.Picker_SetSelectedItem_VerifySelectedItemLabel() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/PickerFeatureTests.cs:line 102
at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** arguments, ObjectHandleOnStack sig, BOOL isConstructor, ObjectHandleOnStack result)
at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** ar
...
Picker_SetIsEnabledFalse_VerifyPickerDisabled
System.InvalidOperationException : Unable to extract difference percentage from exception message.
at Microsoft.Maui.TestCases.Tests.UITest.VerifyScreenshot(String name, Nullable`1 retryDelay, Nullable`1 retryTimeout, Int32 cropLeft, Int32 cropRight, Int32 cropTop, Int32 cropBottom, Double tolerance) in /_/src/Controls/tests/TestCases.Shared.Tests/UITest.cs:line 296
at Microsoft.Maui.TestCases.Tests.PickerFeatureTests.VerifyPickerScreenshot() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/PickerFeatureTests.cs:line 22
at Microsoft.Maui.TestCases.Tests.PickerFeatureTests.Picker_SetIsEnabledFalse_VerifyPickerDisabled() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/PickerFeatureTests.cs:line 260
at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** arguments, ObjectHandleOnStack sig, BOOL isConstructor, ObjectHandleOnStack result)
at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** arg
...
Picker_SetSelectedIndex_VerifySelectedIndexAndItem
System.InvalidOperationException : Unable to extract difference percentage from exception message.
at Microsoft.Maui.TestCases.Tests.UITest.VerifyScreenshot(String name, Nullable`1 retryDelay, Nullable`1 retryTimeout, Int32 cropLeft, Int32 cropRight, Int32 cropTop, Int32 cropBottom, Double tolerance) in /_/src/Controls/tests/TestCases.Shared.Tests/UITest.cs:line 296
at Microsoft.Maui.TestCases.Tests.PickerFeatureTests.VerifyPickerScreenshot() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/PickerFeatureTests.cs:line 22
at Microsoft.Maui.TestCases.Tests.PickerFeatureTests.Picker_SetSelectedIndex_VerifySelectedIndexAndItem() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/PickerFeatureTests.cs:line 85
at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** arguments, ObjectHandleOnStack sig, BOOL isConstructor, ObjectHandleOnStack result)
at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void**
...
Issue32984PickerShouldResize
System.TimeoutException : Timed out waiting for element...
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.Issue32984.Issue32984PickerShouldResize() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue32984.cs:line 26
at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** arguments, ObjectHandleOnStack sig
...
InvisibleDatepickerShowsDialogOnFocus
System.TimeoutException : Timed out waiting for element...
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.Issue5159.InvisibleDatepickerShowsDialogOnFocus() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/XFIssue/Issue5159.cs:line 25
at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** arguments, ObjectHa
...
Picker_SetFontSizeAndFontAttributesBold_VerifyFontSizeAndAttributes
System.InvalidOperationException : Unable to extract difference percentage from exception message.
at Microsoft.Maui.TestCases.Tests.UITest.VerifyScreenshot(String name, Nullable`1 retryDelay, Nullable`1 retryTimeout, Int32 cropLeft, Int32 cropRight, Int32 cropTop, Int32 cropBottom, Double tolerance) in /_/src/Controls/tests/TestCases.Shared.Tests/UITest.cs:line 296
at Microsoft.Maui.TestCases.Tests.PickerFeatureTests.VerifyPickerScreenshot() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/PickerFeatureTests.cs:line 22
at Microsoft.Maui.TestCases.Tests.PickerFeatureTests.Picker_SetFontSizeAndFontAttributesBold_VerifyFontSizeAndAttributes() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/PickerFeatureTests.cs:line 165
at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** arguments, ObjectHandleOnStack sig, BOOL isConstructor, ObjectHandleOnStack result)
at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnSt
...
Picker_SetFontAttributesItalicAndFontFamilyDokdo_VerifyFontAttributesAndFontFamily
System.InvalidOperationException : Unable to extract difference percentage from exception message.
at Microsoft.Maui.TestCases.Tests.UITest.VerifyScreenshot(String name, Nullable`1 retryDelay, Nullable`1 retryTimeout, Int32 cropLeft, Int32 cropRight, Int32 cropTop, Int32 cropBottom, Double tolerance) in /_/src/Controls/tests/TestCases.Shared.Tests/UITest.cs:line 296
at Microsoft.Maui.TestCases.Tests.PickerFeatureTests.VerifyPickerScreenshot() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/PickerFeatureTests.cs:line 22
at Microsoft.Maui.TestCases.Tests.PickerFeatureTests.Picker_SetFontAttributesItalicAndFontFamilyDokdo_VerifyFontAttributesAndFontFamily() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/PickerFeatureTests.cs:line 245
at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** arguments, ObjectHandleOnStack sig, BOOL isConstructor, ObjectHandleOnStack result)
at System.RuntimeMethodHandle.InvokeMethod(O
...
VerifyPickerItemDisplayBindingValue
System.InvalidOperationException :
Snapshot different than baseline: VerifyPickerItemDisplayBindingValue.png (size differs - baseline is 1124x2286 pixels, actual is 1206x2472 pixels)
If the correct baseline has changed (this isn't a a bug), then update the baseline image.
See test attachment or download the build artifacts to get the new snapshot file.
More info: https://aka.ms/visual-test-workflow
iOS 26 visual tests require an iPhone 11 Pro simulator for correct screen resolution.
To create the simulator, run:
xcrun simctl create "iPhone 11 Pro" com.apple.CoreSimulator.SimDeviceType.iPhone-11-Pro com.apple.CoreSimulator.SimRuntime.iOS-26-0
Then run the tests targeting the new simulator.
----> VisualTestUtils.VisualTestFailedException :
Snapshot different than baseline: VerifyPickerItemDisplayBindingValue.png (size differs - baseline is 1124x2286 pixels, actual is 1206x2472 pixels)
If the correct baseline has changed (this isn't a a bug), then update the baseline image.
See
...
Picker_SetFlowDirectionRTL_VerifyFlowDirection
System.InvalidOperationException : Unable to extract difference percentage from exception message.
at Microsoft.Maui.TestCases.Tests.UITest.VerifyScreenshot(String name, Nullable`1 retryDelay, Nullable`1 retryTimeout, Int32 cropLeft, Int32 cropRight, Int32 cropTop, Int32 cropBottom, Double tolerance) in /_/src/Controls/tests/TestCases.Shared.Tests/UITest.cs:line 296
at Microsoft.Maui.TestCases.Tests.PickerFeatureTests.VerifyPickerScreenshot() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/PickerFeatureTests.cs:line 22
at Microsoft.Maui.TestCases.Tests.PickerFeatureTests.Picker_SetFlowDirectionRTL_VerifyFlowDirection() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/PickerFeatureTests.cs:line 205
at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** arguments, ObjectHandleOnStack sig, BOOL isConstructor, ObjectHandleOnStack result)
at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** ar
...
Issue16737Test
System.InvalidOperationException :
Snapshot different than baseline: Issue16737Test.png (size differs - baseline is 1124x2286 pixels, actual is 1206x2472 pixels)
If the correct baseline has changed (this isn't a a bug), then update the baseline image.
See test attachment or download the build artifacts to get the new snapshot file.
More info: https://aka.ms/visual-test-workflow
iOS 26 visual tests require an iPhone 11 Pro simulator for correct screen resolution.
To create the simulator, run:
xcrun simctl create "iPhone 11 Pro" com.apple.CoreSimulator.SimDeviceType.iPhone-11-Pro com.apple.CoreSimulator.SimRuntime.iOS-26-0
Then run the tests targeting the new simulator.
----> VisualTestUtils.VisualTestFailedException :
Snapshot different than baseline: Issue16737Test.png (size differs - baseline is 1124x2286 pixels, actual is 1206x2472 pixels)
If the correct baseline has changed (this isn't a a bug), then update the baseline image.
See test attachment or download the build arti
...
Picker_SetFontSizeAndFontFamilyDokdo_VerifyFontSizeAndFontFamily
System.InvalidOperationException : Unable to extract difference percentage from exception message.
at Microsoft.Maui.TestCases.Tests.UITest.VerifyScreenshot(String name, Nullable`1 retryDelay, Nullable`1 retryTimeout, Int32 cropLeft, Int32 cropRight, Int32 cropTop, Int32 cropBottom, Double tolerance) in /_/src/Controls/tests/TestCases.Shared.Tests/UITest.cs:line 296
at Microsoft.Maui.TestCases.Tests.PickerFeatureTests.VerifyPickerScreenshot() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/PickerFeatureTests.cs:line 22
at Microsoft.Maui.TestCases.Tests.PickerFeatureTests.Picker_SetFontSizeAndFontFamilyDokdo_VerifyFontSizeAndFontFamily() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/PickerFeatureTests.cs:line 187
at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** arguments, ObjectHandleOnStack sig, BOOL isConstructor, ObjectHandleOnStack result)
at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack
...
Picker_SetVerticalTextAlignmentAndSelectedItem_VerifySelectedItem
System.InvalidOperationException : Unable to extract difference percentage from exception message.
at Microsoft.Maui.TestCases.Tests.UITest.VerifyScreenshot(String name, Nullable`1 retryDelay, Nullable`1 retryTimeout, Int32 cropLeft, Int32 cropRight, Int32 cropTop, Int32 cropBottom, Double tolerance) in /_/src/Controls/tests/TestCases.Shared.Tests/UITest.cs:line 296
at Microsoft.Maui.TestCases.Tests.PickerFeatureTests.VerifyPickerScreenshot() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/PickerFeatureTests.cs:line 22
at Microsoft.Maui.TestCases.Tests.PickerFeatureTests.Picker_SetVerticalTextAlignmentAndSelectedItem_VerifySelectedItem() in /_/src/Controls/tests/TestCases.Shared.Tests/Tests/FeatureMatrix/PickerFeatureTests.cs:line 329
at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStack target, Void** arguments, ObjectHandleOnStack sig, BOOL isConstructor, ObjectHandleOnStack result)
at System.RuntimeMethodHandle.InvokeMethod(ObjectHandleOnStac
...
BlankScreenOnNavigationBack
System.InvalidOperationException :
Snapshot different than baseline: BlankScreenOnNavigationBack.png (size differs - baseline is 1124x2286 pixels, actual is 1206x2472 pixels)
If the correct baseline has changed (this isn't a a bug), then update the baseline image.
See test attachment or download the build artifacts to get the new snapshot file.
More info: https://aka.ms/visual-test-workflow
iOS 26 visual tests require an iPhone 11 Pro simulator for correct screen resolution.
To create the simulator, run:
xcrun simctl create "iPhone 11 Pro" com.apple.CoreSimulator.SimDeviceType.iPhone-11-Pro com.apple.CoreSimulator.SimRuntime.iOS-26-0
Then run the tests targeting the new simulator.
----> VisualTestUtils.VisualTestFailedException :
Snapshot different than baseline: BlankScreenOnNavigationBack.png (size differs - baseline is 1124x2286 pixels, actual is 1206x2472 pixels)
If the correct baseline has changed (this isn't a a bug), then update the baseline image.
See test attachment
...
📎 Download drop-deep-uitests artifact (TRX + snapshot diffs)
Pre-Flight — Context & Validation
Issue: #25634 - Picker does not refresh displayed item when bound property changes through ItemDisplayBinding
PR: #29922 - Picker: Refresh ItemDisplayBinding when bound item properties change
Platforms Affected: Android, iOS, MacCatalyst, Windows (testing platform requested: iOS)
Files Changed: 8 implementation/API, 7 test/snapshot
Key Findings
- PR changes
Pickerto subscribe toINotifyPropertyChangeditems whenItemDisplayBindingis set and callsResetItems()when the bound item property changes. - PR adds UI test coverage for issue #25634 with platform snapshots.
ghis unauthenticated; public PR metadata was fetched via GitHub REST and required checks could not be verified locally.- Gate result was provided by caller: Gate ✅ PASSED — tests fail without fix and pass with PR fix. Gate was not re-run.
Code Review Summary
Verdict: NEEDS_CHANGES
Confidence: low
Errors: 3 | Warnings: 0 | Suggestions: 0
Key code review findings:
- ❌
src/Controls/src/Core/Picker/Picker.cs:398Handler detach removes item subscriptions with no reconnect re-subscribe path. - ❌
src/Controls/src/Core/Picker/Picker.cs:427NotifyCollectionChangedAction.Resetwith nullOldItems/NewItemscan leak old item subscriptions and miss new current items. - ❌
src/Controls/src/Core/Picker/Picker.cs:415Nested paths such asAddress.Namedo not refresh when the root propertyAddresschanges.
Fix Candidates
| # | Source | Approach | Test Result | Files Changed | Notes |
|---|---|---|---|---|---|
| PR | PR #29922 | Subscribe each INotifyPropertyChanged item and call ResetItems() when PropertyName equals the ItemDisplayBinding path. |
✅ PASSED (Gate) | src/Controls/src/Core/Picker/Picker.cs, PublicAPI files, UI tests/snapshots |
Original PR; code review found lifecycle/reset/nested-path gaps. |
Code Review — Deep Analysis
Code Review — PR #29922
Independent Assessment
What this changes: Picker now subscribes to INotifyPropertyChanged items in ItemsSource when ItemDisplayBinding is set, and refreshes displayed picker items via ResetItems() when item properties change. It also adds UI screenshot coverage.
Inferred motivation: Fix stale Picker display text when bound item view-model properties change after initial item rendering.
Reconciliation with PR Narrative
Author claims: Fixes #25634 by refreshing Picker.ItemDisplayBinding when bound item properties change, including item additions/removals.
Agreement/disagreement: The basic top-level property scenario (Binding("LastName")) is addressed, but lifecycle, reset collection changes, and nested binding paths remain incorrect.
Prior Review Reconciliation
| Prior ❌ Error Finding | Source | Status | Evidence |
|---|---|---|---|
| Handler detach/reconnect loses item property subscriptions | MauiBot inline [major] |
❌ Unresolved | Current Picker.cs:392-398 unsubscribes when NewHandler == null; OnHandlerChanged does not re-subscribe. |
| Collection reset leaks old subscriptions / misses reset items | MauiBot inline [major] |
❌ Unresolved | Current Picker.cs:425-430 only uses e.OldItems/e.NewItems, which are commonly null for Reset. |
| Nested binding paths are missed | MauiBot inline [major] |
❌ Unresolved | Current Picker.cs:413-416 compares PropertyName to the full binding path. |
Earlier gate failure on commit 920a2cc |
MauiBot review body | 🔄 Obsolete/undetermined | Current public check-runs for head 41bf371 appear completed success/skipped, but required checks could not be verified due unauthenticated gh. |
Blast Radius Assessment
- Runs for all instances: No — only Pickers with non-null
ItemDisplayBinding, but this is core control behavior. - Startup impact: No.
- Static/shared state: No.
- Handler lifecycle impact: Yes — subscribes item events across handler attach/detach.
CI Status
- Required-check result: undetermined
- Classification: tool-unavailable for required-check query
- Action taken:
gh pr checks 29922 --repo dotnet/maui --requiredreturned authentication guidance. Public GitHub check-runs for head were queried and appeared successful/skipped, but required-check status is not verifiable; confidence capped low.
Findings
❌ Error — Handler reconnect permanently disables item refresh
src/Controls/src/Core/Picker/Picker.cs:398
When the Picker loses its handler, OnHandlerChanging unsubscribes from all item PropertyChanged events. There is no matching re-subscribe when the same Picker receives a handler again. Shell tab switches, navigation detach/reattach, or handler recreation can leave the Picker unable to refresh ItemDisplayBinding changes after reconnect.
❌ Error — Reset collection changes leak subscriptions and miss current items
src/Controls/src/Core/Picker/Picker.cs:427
NotifyCollectionChangedAction.Reset often has OldItems == null and NewItems == null. The current code therefore cannot unsubscribe removed items or subscribe the collection’s current items after a reset-style refresh. Removed view models may retain the Picker and continue firing stale callbacks, while newly reset items may not refresh on property changes.
❌ Error — Nested binding paths do not refresh on root property changes
src/Controls/src/Core/Picker/Picker.cs:415
For ItemDisplayBinding = new Binding("Address.Name"), replacing Address usually raises PropertyChanged("Address"), not "Address.Name". The exact string comparison skips that valid invalidation, leaving Picker display text stale for nested bindings.
Failure-Mode Probing
- Handler disconnect/reconnect: subscriptions are removed on disconnect and never restored, so refresh stops.
ObservableCollection.Clear()/ reset:OldItemsis commonly null, so old items remain subscribed.- Nested object replacement:
PropertyChanged("Address")does not match"Address.Name", so display does not update.
Verdict: NEEDS_CHANGES
Confidence: low
Summary: The core scenario is improved, but three concrete correctness issues remain in lifecycle, collection reset handling, and nested binding invalidation. Required CI status could not be verified with unauthenticated gh, and prior major findings remain unresolved.
Fix — Analysis & Comparison
Fix Candidates
| # | Source | Approach | Test Result | Files Changed | Notes |
|---|---|---|---|---|---|
| 1 | try-fix-1 / claude-opus-4.6 | HashSet-tracked item subscriptions, re-evaluate full binding on any item property change, then update the changed display string directly. | ✅ PASS | 11 files | Passed iOS Issue25634, but added LockableObservableListWrapper.InternalSetItem public API and PublicAPI entries; not selected because the API surface increase is unnecessary for this Picker-only bug. |
| 2 | try-fix-2 / claude-opus-4.7 | Picker-private HashSet<INotifyPropertyChanged> rebuilt from current ItemsSource on source/binding/collection/handler changes; smart path matching supports full path, root segment for nested/indexed paths, null/empty, and non-Binding refresh. |
✅ PASS | 1 file | Selected: fixes handler reconnect, reset subscription leaks/misses, and nested path invalidation without public API churn. Self-review clean. |
| PR | PR #29922 | Subscribe INotifyPropertyChanged items from ItemsSource and call ResetItems() when PropertyName exactly matches Binding.Path. |
✅ PASSED (Gate) | 15 files | Original PR; gate passed, but code review found unresolved lifecycle/reset/nested-path gaps. |
Cross-Pollination
| Model | Round | New Ideas? | Details |
|---|---|---|---|
| claude-opus-4.6 | 1 | Yes | Candidate 1 proved that binding re-evaluation on item change passes the iOS regression and handles nested paths, but its targeted item update required new public API. |
| claude-opus-4.7 | 1 | Yes | Candidate 2 incorporated candidate 1's lessons while avoiding public API by using existing ResetItems() and Picker-private subscription tracking. |
Exhausted: No — stopped because Candidate #2 passed all requested tests and is demonstrably better than the PR's current fix and Candidate #1.
Selected Fix: Candidate #2 — it passes the iOS regression, keeps the change isolated to Picker.cs, avoids public API additions, and directly addresses all three expert-review defects: handler reconnect, collection reset, and nested binding paths.
Candidate Details
try-fix-1
- Output:
CustomAgentLogsTmp/PRState/29922/PRAgent/try-fix-1/content.md - Attempt artifacts:
CustomAgentLogsTmp/PRState/29922/PRAgent/try-fix/attempt-1/ - Result: Pass
- Failure analysis: Not failed; rejected as best fix because it introduces unnecessary public API surface and PublicAPI churn.
try-fix-2
- Output:
CustomAgentLogsTmp/PRState/29922/PRAgent/try-fix-2/content.md - Attempt artifacts:
CustomAgentLogsTmp/PRState/29922/PRAgent/try-fix/attempt-2/ - Result: Pass
- Failure analysis: Not failed; first iteration hit CA1307 analyzer errors for
IndexOf(char), fixed withStringComparison.Ordinal, then iOS UI test passed.
Report — Final Recommendation
Comparative Fix Report — PR #29922
Candidates compared
| Rank | Candidate | Regression result | Assessment |
|---|---|---|---|
| 1 | try-fix-2 |
PASS | Best candidate. It fixes the PR's verified scenario and all expert-review defects: handler reconnect, collection reset subscription correctness, and nested/indexed binding path invalidation. It is localized to Picker.cs and adds no public API. |
| 2 | pr-plus-reviewer |
Not independently re-run; equivalent feedback is covered by try-fix-2 |
The expert-feedback application is the right direction and maps to the same Picker-private rebuild strategy as try-fix-2, but the separately recorded passing test evidence belongs to try-fix-2. |
| 3 | try-fix-1 |
PASS | Correctly handles lifecycle, reset, and nested path cases, but does so by adding LockableObservableListWrapper.InternalSetItem public API and corresponding PublicAPI entries for a Picker-only bug. That API churn is unnecessary. |
| 4 | pr |
PASS for provided gate only | The raw PR passes the provided top-level iOS gate, but expert review found unresolved correctness defects for handler reconnect, collection reset, and nested binding paths. |
Winning candidate
Winner: try-fix-2
try-fix-2 is the single strongest candidate because it passed the requested iOS regression and addresses every actionable expert-review issue without expanding public API surface. The raw PR must rank below it despite passing the gate because its implementation still has lifecycle and correctness gaps; try-fix-1 must rank below it because its public API addition is unnecessary for this localized Picker fix.
Notes
- No candidate with a failed regression test outranks a passing candidate.
ghrequired-check queries were blocked by missing authentication, so CI state was not used to promote any untested candidate above a tested one.
Future Action — alternative fix proposed (try-fix-2)
Automated review — alternative fix proposed
The expert-reviewer evaluation compared the PR fix against automatically generated candidates and selected try-fix-2 as the strongest fix.
Why: try-fix-2 passed the requested iOS regression and fixes all expert-review defects: handler reconnect, collection Reset subscription correctness, and nested/indexed binding path invalidation. It keeps the change localized to Picker.cs and avoids the unnecessary public API expansion in try-fix-1.
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-2)
diff --git a/src/Controls/src/Core/Picker/Picker.cs b/src/Controls/src/Core/Picker/Picker.cs
index 2b8f363bbf..6320af9f9f 100644
--- a/src/Controls/src/Core/Picker/Picker.cs
+++ b/src/Controls/src/Core/Picker/Picker.cs
@@ -237,7 +237,7 @@ namespace Microsoft.Maui.Controls
return;
OnPropertyChanging();
- var oldValue = value;
+ var oldValue = _itemDisplayBinding;
_itemDisplayBinding = value;
OnItemDisplayBindingChanged(oldValue, _itemDisplayBinding);
OnPropertyChanged();
@@ -274,6 +274,31 @@ namespace Microsoft.Maui.Controls
return (string)GetValue(s_displayProperty);
}
+ // Tracks INotifyPropertyChanged items in ItemsSource that we have subscribed to.
+ // Kept independent of NotifyCollectionChangedEventArgs (which can have null OldItems/NewItems on Reset)
+ // and of handler attach/detach state, so we can always unsubscribe what we actually subscribed to.
+ // Reference equality ensures distinct item instances are tracked separately even if they override Equals.
+ readonly HashSet<INotifyPropertyChanged> _subscribedItems = new HashSet<INotifyPropertyChanged>(ReferenceEqualityComparer.Instance);
+
+ void RebuildItemSubscriptions()
+ {
+ // Unsubscribe what we currently track.
+ foreach (var npc in _subscribedItems)
+ npc.PropertyChanged -= OnPickerItemPropertyChanged;
+ _subscribedItems.Clear();
+
+ // Only subscribe when we have a display binding AND a live handler — without a handler
+ // there is nothing to update visually, and we re-subscribe in OnHandlerChanged.
+ if (ItemDisplayBinding is null || ItemsSource is null || Handler is null)
+ return;
+
+ foreach (var item in ItemsSource)
+ {
+ if (item is INotifyPropertyChanged npc && _subscribedItems.Add(npc))
+ npc.PropertyChanged += OnPickerItemPropertyChanged;
+ }
+ }
+
static object CoerceSelectedIndex(BindableObject bindable, object value)
{
var picker = (Picker)bindable;
@@ -282,6 +307,7 @@ namespace Microsoft.Maui.Controls
void OnItemDisplayBindingChanged(BindingBase oldValue, BindingBase newValue)
{
+ RebuildItemSubscriptions();
ResetItems();
}
@@ -325,6 +351,10 @@ namespace Microsoft.Maui.Controls
((LockableObservableListWrapper)Items).IsLocked = false;
((LockableObservableListWrapper)Items).InternalClear();
}
+
+ // Rebuild item subscriptions from the new source — handles oldValue items being unsubscribed
+ // and newValue items being subscribed (when ItemDisplayBinding is set and a handler exists).
+ RebuildItemSubscriptions();
}
readonly Queue<Action> _pendingIsOpenActions = new Queue<Action>();
@@ -345,6 +375,10 @@ namespace Microsoft.Maui.Controls
{
base.OnHandlerChanged();
+ // Re-establish item subscriptions whenever the handler attaches/detaches,
+ // so a Picker that gets disconnected and later reattached still tracks item changes.
+ RebuildItemSubscriptions();
+
// Process any pending actions when handler becomes available
while (_pendingIsOpenActions.Count > 0 && Handler != null)
{
@@ -364,8 +398,64 @@ namespace Microsoft.Maui.Controls
picker.Closed?.Invoke(picker, PickerClosedEventArgs.Empty);
}
+ void OnPickerItemPropertyChanged(object sender, PropertyChangedEventArgs e)
+ {
+ if (ItemDisplayBinding is null)
+ return;
+
+ if (ItemDisplayBinding is Binding binding)
+ {
+ var path = binding.Path;
+
+ // A null/empty PropertyName means "all properties may have changed" (INPC convention).
+ // A null/empty binding path also means the whole item is the display value.
+ if (string.IsNullOrEmpty(e.PropertyName) || string.IsNullOrEmpty(path))
+ {
+ ResetItems();
+ return;
+ }
+
+ // Full-path match (e.g. "Name" matches "Name").
+ if (path == e.PropertyName)
+ {
+ ResetItems();
+ return;
+ }
+
+ // Nested-path root match (e.g. binding path "Address.Name" should refresh
+ // when the root property "Address" itself changes — the sub-tree was swapped out).
+ var dotIndex = path.IndexOf('.', StringComparison.Ordinal);
+ if (dotIndex > 0 && string.CompareOrdinal(path, 0, e.PropertyName, 0, dotIndex) == 0
+ && e.PropertyName.Length == dotIndex)
+ {
+ ResetItems();
+ return;
+ }
+
+ // Indexed-path root match (e.g. "Items[0].Name" — refresh if "Items" itself swaps).
+ var bracketIndex = path.IndexOf('[', StringComparison.Ordinal);
+ if (bracketIndex > 0 && string.CompareOrdinal(path, 0, e.PropertyName, 0, bracketIndex) == 0
+ && e.PropertyName.Length == bracketIndex)
+ {
+ ResetItems();
+ return;
+ }
+ }
+ else
+ {
+ // MultiBinding or any other BindingBase: we cannot reliably introspect which
+ // property feeds the converter, so refresh on any item-level property change.
+ ResetItems();
+ }
+ }
+
void CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
+ // Always rebuild from the current ItemsSource — this correctly handles Reset (where
+ // OldItems/NewItems are typically null) and avoids leaking subscriptions to items
+ // that have been removed.
+ RebuildItemSubscriptions();
+
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
kubaflo
left a comment
There was a problem hiding this comment.
Could you please check the ai's suggestions?
|
/review rerun |



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
Picker does not refresh displayed item when bound property changes through ItemDisplayBinding
Description of Change
Added support to automatically refresh the Picker display when a bound item's property changes. Subscribed to property change events in the items source, and updated the display when the property defined in ItemDisplayBinding changes. Also handled item additions and removals by updating the subscriptions accordingly.
Issues Fixed
Fixes #25634
Tested the behavior in the following platforms.
iOS-BeforeFix.mov
iOS-AfterFix.mov