Improved Unfocus support for Picker on Mac Catalyst#33127
Improved Unfocus support for Picker on Mac Catalyst#33127PureWeen merged 2 commits intodotnet:inflight/currentfrom
Conversation
There was a problem hiding this comment.
Pull request overview
This PR enhances MacCatalyst Picker functionality by implementing proper programmatic dismissal via the Unfocus command, addressing issue #30897. The implementation enables external code to close the picker dialog and properly manages focus states.
Key changes:
- Added UIAlertController instance tracking for MacCatalyst to enable programmatic dismissal
- Implemented MapUnfocus command handler to support Unfocus() API on MacCatalyst
- Simplified dismiss logic by removing duplicate event handlers
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| src/Core/src/Handlers/Picker/PickerHandler.iOS.cs | Added MacCatalyst-specific pickerController field, implemented MapUnfocus method for programmatic dismissal, and streamlined dismiss logic by removing EditingDidEnd event handler |
| src/Core/src/Handlers/Picker/PickerHandler.cs | Registered Unfocus command in CommandMapper for MacCatalyst platform |
|
@kubaflo Issue2339 test scenario fails after this changes. The MapUnfocus implementation has a logic bug on line 165. Can you check this? In Issue2339 sample, when you click pickerBtn3 (Focus → wait 2s → Unfocus): |
|
@sheiksyedm sure! Thanks for letting me know! |
PR Review: #33127 - Improved Unfocus support for Picker on Mac CatalystDate: 2026-01-16 | Issue: #30897, #30891 | PR: #33127 ⛔ Status: GATE FAILED - Request Changes
⛔ Gate Result: FAILEDVerdict: ❌ REQUEST CHANGES Critical Issue: Line 165 logic bug prevents Unfocus from working 📋 Issue SummaryIssue #30897: VoiceOver users unable to access expanded Picker list on MacCatalyst Root Cause: MacCatalyst Picker lacked Unfocus command handler and used problematic EditingDidEnd event Platforms Affected: MacCatalyst (primary), iOS (shares code) 🔍 Root Cause AnalysisThe Bug on Line 165Current Code (PickerHandler.iOS.cs:161-171): internal static void MapUnfocus(IPickerHandler handler, IPicker picker, object? args)
{
if (handler is PickerHandler pickerHandler &&
pickerHandler.pickerController is not null &&
pickerHandler.pickerController.PresentedViewController is not null) // ← BUG HERE
{
pickerHandler.pickerController.DismissViewControllerAsync(true);
if (handler.VirtualView is IPicker virtualView)
virtualView.IsFocused = virtualView.IsOpen = false;
}
}Why This is Wrong:
Test Failure Scenario (Issue2339.FocusAndUnFocusMultipleTimes):
🔧 Proposed FixRemove the PresentedViewController check: internal static void MapUnfocus(IPickerHandler handler, IPicker picker, object? args)
{
if (handler is PickerHandler pickerHandler &&
pickerHandler.pickerController is not null) // ← Remove PresentedViewController check
{
pickerHandler.pickerController.DismissViewControllerAsync(true);
if (handler.VirtualView is IPicker virtualView)
virtualView.IsFocused = virtualView.IsOpen = false;
}
}Why This Works:
🐛 Additional Issues FoundIssue 2: No await on async dismissal (Line 167)Problem: pickerHandler.pickerController.DismissViewControllerAsync(true); // Not awaited
if (handler.VirtualView is IPicker virtualView)
virtualView.IsFocused = virtualView.IsOpen = false; // Executes immediatelyRisk: State updates execute before dismissal animation completes Fix: Either await the dismissal or use synchronous dismiss if state must update immediately Issue 3: Memory leak - no cleanup in DisconnectHandler (Line 14)Problem: Fix: Add cleanup in protected override void DisconnectHandler(MauiPicker platformView)
{
_proxy.Disconnect(platformView);
#if MACCATALYST
if (_pickerController != null)
{
_pickerController.DismissViewController(false, null);
_pickerController = null;
}
#endif
if (_pickerView != null) { ... }
}Issue 4: Naming convention (Line 14)Problem: Fix: Rename field to ✅ What Works Well
📋 RecommendationMust Fix:
Should Fix: After fixes: Run Issue2339 test to verify Unfocus works correctly Test ValidationTest: Issue2339.FocusAndUnFocusMultipleTimes
Summary for PR AuthorYour overall approach is excellent:
However, line 165 has a logic error that prevents Unfocus from working. The test Issue2339 correctly fails because the condition check is backwards - it checks if the picker has presented something (always false) instead of just checking if the picker exists. Fix line 165 and the other issues noted above, and this PR will be ready to merge! 🎉 |
Adds a detailed review report for PR dotnet#33127, identifying a logic bug in the Picker Unfocus implementation on Mac Catalyst. The report requests changes to fix the condition preventing Unfocus from working, recommends awaiting async dismissal, cleaning up pickerController in DisconnectHandler, and renaming for consistency.
Introduces the MapUnfocus mapping for the PickerHandler on Mac Catalyst, enabling proper dismissal of the picker controller and updating focus state. Refactors related code to store the UIAlertController instance and ensures IsFocused and IsOpen are set to false when the picker is dismissed. Gate PASSED: Issue2339 test validates MapUnfocus fix on MacCatalyst Fix MapUnfocus bug - remove incorrect PresentedViewController check - Made MapUnfocus async void to properly await dismissal - Removed PresentedViewController null check (always false when picker showing) - Added await to DismissViewControllerAsync for proper state management Fixes line 165 bug reported by @sheiksyedm that prevented Unfocus from working. Add PR review report for Picker Unfocus fix on Mac Catalyst Adds a detailed review report for PR dotnet#33127, identifying a logic bug in the Picker Unfocus implementation on Mac Catalyst. The report requests changes to fix the condition preventing Unfocus from working, recommends awaiting async dismissal, cleaning up pickerController in DisconnectHandler, and renaming for consistency. Agent's feedback suggestion Update PickerHandler.iOS.cs
Introduces the MapUnfocus mapping for the PickerHandler on Mac Catalyst, enabling proper dismissal of the picker controller and updating focus state. Refactors related code to store the UIAlertController instance and ensures IsFocused and IsOpen are set to false when the picker is dismissed. Gate PASSED: Issue2339 test validates MapUnfocus fix on MacCatalyst Fix MapUnfocus bug - remove incorrect PresentedViewController check - Made MapUnfocus async void to properly await dismissal - Removed PresentedViewController null check (always false when picker showing) - Added await to DismissViewControllerAsync for proper state management Fixes line 165 bug reported by @sheiksyedm that prevented Unfocus from working. Add PR review report for Picker Unfocus fix on Mac Catalyst Adds a detailed review report for PR dotnet#33127, identifying a logic bug in the Picker Unfocus implementation on Mac Catalyst. The report requests changes to fix the condition preventing Unfocus from working, recommends awaiting async dismissal, cleaning up pickerController in DisconnectHandler, and renaming for consistency. Agent's feedback suggestion Update PickerHandler.iOS.cs
Introduces the MapUnfocus mapping for the PickerHandler on Mac Catalyst, enabling proper dismissal of the picker controller and updating focus state. Refactors related code to store the UIAlertController instance and ensures IsFocused and IsOpen are set to false when the picker is dismissed. Gate PASSED: Issue2339 test validates MapUnfocus fix on MacCatalyst Fix MapUnfocus bug - remove incorrect PresentedViewController check - Made MapUnfocus async void to properly await dismissal - Removed PresentedViewController null check (always false when picker showing) - Added await to DismissViewControllerAsync for proper state management Fixes line 165 bug reported by @sheiksyedm that prevented Unfocus from working. Add PR review report for Picker Unfocus fix on Mac Catalyst Adds a detailed review report for PR dotnet#33127, identifying a logic bug in the Picker Unfocus implementation on Mac Catalyst. The report requests changes to fix the condition preventing Unfocus from working, recommends awaiting async dismissal, cleaning up pickerController in DisconnectHandler, and renaming for consistency. Agent's feedback suggestion Update PickerHandler.iOS.cs
🤖 PR Agent Review📊 Expand Full ReviewStatus: ✅ APPROVE
🔍 Phase 1: Pre-Flight — Context & Validation📝 Review Session — Update PickerHandler.iOS.cs ·
|
| # | Source | Approach | Test Result | Files Changed | Notes |
|---|---|---|---|---|---|
| PR | PR #33127 | Remove EditingDidEnd handler, add pickerController field, implement MapUnfocus | ✅ PASS (Gate) | PickerHandler.iOS.cs (+29/-14), PickerHandler.cs (+2) | Original PR - line 165 bug fixed ✅ |
PR's Approach:
- Added
UIAlertController? pickerControllerfield to track picker instance - Removed
EditingDidEndevent handler (was causing duplicate dismiss calls) - Implemented
MapUnfocusmethod to programmatically dismiss picker - Registered Unfocus command in CommandMapper for MacCatalyst
- Fixed line 165 to remove incorrect
PresentedViewControllercheck
Exhausted: Yes (Analysis-based determination - see reasoning below)
Selected Fix: PR's fix with recommendations for improvements
Fix Comparison Analysis:
PR's Approach (✅ PASS):
- Store
UIAlertControllerreference as instance field - Remove
EditingDidEndevent handler - Implement
MapUnfocusto dismiss controller - Register command in CommandMapper for MacCatalyst
Why PR's fix works:
- ✅ Follows Android's pattern (register command → implement handler → dismiss dialog)
- ✅ Properly scopes pickerController reference for external access
- ✅ Fixes VoiceOver issue by removing problematic EditingDidEnd
- ✅ Minimal changes (2 files, ~30 lines)
Alternative approaches considered:
| Alternative | Why NOT pursued |
|---|---|
| Fix EditingDidEnd approach | ❌ Event timing causes VoiceOver issues (documented in PR) |
| Use PresentedViewController tracking | ❌ Prior review found this doesn't work (line 165 bug) |
| Store controller in MauiPicker | ❌ Requires MauiPicker changes, more complex |
| Use global dictionary | ❌ Over-engineered for simple reference storage |
Exhaustion reasoning:
All viable approaches require the same fundamental solution:
- Store UIAlertController reference somehow
- Implement MapUnfocus to dismiss it
- Register the command
The PR's field-based approach is the simplest and follows existing patterns. Alternative storage mechanisms (dictionary, attached properties, etc.) would add complexity without benefit.
Recommended improvements:
- Rename
pickerControllerto_pickerController(C# field naming convention) - Add cleanup in
DisconnectHandlerto prevent memory leaks - Consider awaiting async dismissal with proper error handling
📋 Phase 5: Report — Final Recommendation
📝 Review Session — Post pr comment skill - improved · 234d49e
Status: ✅ COMPLETE
Final Recommendation
Verdict: ✅ APPROVE - Fix is correct and addresses the root cause effectively
Key Findings
✅ Strengths:
- Core fix is correct: PR successfully implements
MapUnfocuscommand for MacCatalyst - Critical bug fixed: Line 165 bug from prior review (incorrect
PresentedViewControllercheck) has been resolved - Tests validate fix: Issue2339.FocusAndUnFocusMultipleTimes passes with the fix, failed without it
- Follows platform patterns: Implementation mirrors Android's approach (register command → implement handler → dismiss dialog)
- Minimal changes: Only 2 files modified, ~30 lines total - surgical fix
- Proper async handling: Line 166 now correctly awaits
DismissViewControllerAsync
- Field naming:
pickerControllershould be_pickerControllerper C# conventions - Memory management: No cleanup in
DisconnectHandler- potential memory leak when handler disconnects - Error handling: Async dismissal could benefit from try-catch for edge cases
Root Cause Summary
Problem: MacCatalyst Picker displayed as UIAlertController but lacked programmatic dismissal capability. The Unfocus command wasn't registered, making the control inaccessible to keyboard and VoiceOver users.
Why it occurred:
- iOS non-Catalyst uses UIPickerView with built-in Done button (works fine)
- MacCatalyst uses UIAlertController with custom UIPickerView subview (different implementation)
MapUnfocuswas only implemented for Android (#if ANDROID)pickerControllervariable was method-scoped, inaccessible from external commands- Prior EditingDidEnd approach interfered with VoiceOver accessibility
Impact:
- Severity 1 accessibility issues affecting keyboard-only and VoiceOver users
- Test Issue2339.FocusAndUnFocusMultipleTimes timed out (picker never dismissed programmatically)
Solution Analysis
PR's Approach (Selected):
- Added
UIAlertController? pickerControllerinstance field (line 14) - Removed problematic
EditingDidEndevent handler - Implemented
MapUnfocusmethod for MacCatalyst (lines 161-170) - Registered
Unfocuscommand in CommandMapper (line 40)
Why this is the best solution:
- ✅ Minimal code changes (2 files, ~30 lines)
- ✅ Follows established Android pattern
- ✅ Fixes VoiceOver issues by removing EditingDidEnd
- ✅ Tests validate the fix works correctly
- ✅ Properly scopes pickerController reference for external access
Alternative approaches considered and rejected:
- Fix EditingDidEnd approach: ❌ Event timing causes VoiceOver issues (documented in PR)
- Use PresentedViewController tracking: ❌ Doesn't work (line 165 bug from prior review)
- Store controller in MauiPicker: ❌ Requires MauiPicker changes, more complex
- Use global dictionary: ❌ Over-engineered for simple reference storage
Optional Improvements
While the fix is ready to merge, consider these minor improvements in a follow-up:
1. Field Naming Convention
// Current
UIAlertController? pickerController;
// Suggested
UIAlertController? _pickerController; // Matches _proxy, _pickerView2. Memory Cleanup in DisconnectHandler
protected override void DisconnectHandler(MauiPicker platformView)
{
_proxy.Disconnect(platformView);
#if MACCATALYST
if (_pickerController != null)
{
_pickerController.DismissViewController(false, null);
_pickerController = null;
}
#endif
if (_pickerView != null) { ... }
}3. Error Handling (Optional)
try
{
await pickerHandler._pickerController.DismissViewControllerAsync(true);
}
catch (ObjectDisposedException)
{
// Already dismissed - safe to ignore
}Comparison with Prior Review
Prior Agent Review (2026-01-16): ❌ REQUEST CHANGES
- Identified critical line 165 bug:
pickerController.PresentedViewController is not nullcheck was incorrect - This check was always null when picker was showing, preventing Unfocus from working
- Test failed due to this bug
Current Review (2026-01-20): ✅ APPROVE
- Line 165 bug has been FIXED ✅
- Line 166 now properly awaits async dismissal ✅
- Tests pass with the fix ✅
- Minor improvements recommended but non-blocking
PR Title and Description
Current PR Title: "Improved Unfocus support for Picker on Mac Catalyst" ✅ Accurate
Description Quality: ✅ Comprehensive
- Clearly explains the changes made
- Documents the fix approach
- Notes platforms affected
- Includes test reference (Issue2339)
No updates needed - title and description accurately reflect the implementation.
📝 Review Session — Update PickerHandler.iOS.cs · 0386e21
Status: ✅ COMPLETE
Final Recommendation
Verdict: ✅ APPROVE - Fix is correct and addresses the root cause effectively
Key Findings
✅ Strengths:
- Core fix is correct: PR successfully implements
MapUnfocuscommand for MacCatalyst - Critical bug fixed: Line 165 bug from prior review (incorrect
PresentedViewControllercheck) has been resolved - Tests validate fix: Issue2339.FocusAndUnFocusMultipleTimes passes with the fix, failed without it
- Follows platform patterns: Implementation mirrors Android's approach (register command → implement handler → dismiss dialog)
- Minimal changes: Only 2 files modified, ~30 lines total - surgical fix
- Proper async handling: Line 166 now correctly awaits
DismissViewControllerAsync
✅ All Issues Resolved:
- Field naming: Changed to
_pickerController(line 14) ✅ - Memory management: Cleanup added in
DisconnectHandler(lines 18-23) ✅ - Error handling: Try-catch added for
ObjectDisposedException(lines 174-180) ✅
Root Cause Summary
Problem: MacCatalyst Picker displayed as UIAlertController but lacked programmatic dismissal capability. The Unfocus command wasn't registered, making the control inaccessible to keyboard and VoiceOver users.
Why it occurred:
- iOS non-Catalyst uses UIPickerView with built-in Done button (works fine)
- MacCatalyst uses UIAlertController with custom UIPickerView subview (different implementation)
MapUnfocuswas only implemented for Android (#if ANDROID)pickerControllervariable was method-scoped, inaccessible from external commands- Prior EditingDidEnd approach interfered with VoiceOver accessibility
Impact:
- Severity 1 accessibility issues affecting keyboard-only and VoiceOver users
- Test Issue2339.FocusAndUnFocusMultipleTimes timed out (picker never dismissed programmatically)
Solution Analysis
PR's Approach (Selected):
- Added
UIAlertController? pickerControllerinstance field (line 14) - Removed problematic
EditingDidEndevent handler - Implemented
MapUnfocusmethod for MacCatalyst (lines 161-170) - Registered
Unfocuscommand in CommandMapper (line 40)
Why this is the best solution:
- ✅ Minimal code changes (2 files, ~30 lines)
- ✅ Follows established Android pattern
- ✅ Fixes VoiceOver issues by removing EditingDidEnd
- ✅ Tests validate the fix works correctly
- ✅ Properly scopes pickerController reference for external access
Alternative approaches considered and rejected:
- Fix EditingDidEnd approach: ❌ Event timing causes VoiceOver issues (documented in PR)
- Use PresentedViewController tracking: ❌ Doesn't work (line 165 bug from prior review)
- Store controller in MauiPicker: ❌ Requires MauiPicker changes, more complex
- Use global dictionary: ❌ Over-engineered for simple reference storage
Optional Improvements
All previously suggested improvements have been implemented! ✅
Implemented Changes:
- ✅ Field Naming Convention: Changed to
_pickerController(line 14) - ✅ Memory Cleanup: Added in
DisconnectHandler(lines 18-23) - ✅ Error Handling: Try-catch added for
ObjectDisposedException(lines 174-180)
Comparison with Prior Review
Prior Agent Review (2026-01-16): ❌ REQUEST CHANGES
- Identified critical line 165 bug:
pickerController.PresentedViewController is not nullcheck was incorrect - This check was always null when picker was showing, preventing Unfocus from working
- Test failed due to this bug
Current Review (2026-01-20): ✅ APPROVE
- Line 165 bug has been FIXED ✅
- Line 166 now properly awaits async dismissal with error handling ✅
- Memory cleanup added in DisconnectHandler ✅
- Field naming fixed to
_pickerController✅ - All recommended improvements implemented ✅
PR Title and Description
Current PR Title: "Improved Unfocus support for Picker on Mac Catalyst" ✅ Accurate
Description Quality: ✅ Comprehensive
- Clearly explains the changes made
- Documents the fix approach
- Notes platforms affected
- Includes test reference (Issue2339)
No updates needed - title and description accurately reflect the implementation.
Introduces the MapUnfocus mapping for the PickerHandler on Mac Catalyst, enabling proper dismissal of the picker controller and updating focus state. Refactors related code to store the UIAlertController instance and ensures IsFocused and IsOpen are set to false when the picker is dismissed. Gate PASSED: Issue2339 test validates MapUnfocus fix on MacCatalyst Fix MapUnfocus bug - remove incorrect PresentedViewController check - Made MapUnfocus async void to properly await dismissal - Removed PresentedViewController null check (always false when picker showing) - Added await to DismissViewControllerAsync for proper state management Fixes line 165 bug reported by @sheiksyedm that prevented Unfocus from working. Add PR review report for Picker Unfocus fix on Mac Catalyst Adds a detailed review report for PR dotnet#33127, identifying a logic bug in the Picker Unfocus implementation on Mac Catalyst. The report requests changes to fix the condition preventing Unfocus from working, recommends awaiting async dismissal, cleaning up pickerController in DisconnectHandler, and renaming for consistency. Agent's feedback suggestion Update PickerHandler.iOS.cs Phase 5: Add comprehensive Report section with final findings and recommendations Phase 5 Report: APPROVE with minor suggestions - Fix is correct and complete Phase 4 Fix: Analysis-based selection - PR's fix is optimal with minor improvements recommended Phase 4: Expand state file for Fix and Report phases Phase 3 Gate: PASSED - Line 165 bug fixed, tests verified Phase 2 Tests: Verify tests exist and compile successfully Phase 1 Pre-Flight: Document PR context and prior review findings
Introduces the MapUnfocus mapping for the PickerHandler on Mac Catalyst, enabling proper dismissal of the picker controller and updating focus state. Refactors related code to store the UIAlertController instance and ensures IsFocused and IsOpen are set to false when the picker is dismissed. Gate PASSED: Issue2339 test validates MapUnfocus fix on MacCatalyst Fix MapUnfocus bug - remove incorrect PresentedViewController check - Made MapUnfocus async void to properly await dismissal - Removed PresentedViewController null check (always false when picker showing) - Added await to DismissViewControllerAsync for proper state management Fixes line 165 bug reported by @sheiksyedm that prevented Unfocus from working. Add PR review report for Picker Unfocus fix on Mac Catalyst Adds a detailed review report for PR dotnet#33127, identifying a logic bug in the Picker Unfocus implementation on Mac Catalyst. The report requests changes to fix the condition preventing Unfocus from working, recommends awaiting async dismissal, cleaning up pickerController in DisconnectHandler, and renaming for consistency. Agent's feedback suggestion Update PickerHandler.iOS.cs Phase 5: Add comprehensive Report section with final findings and recommendations Phase 5 Report: APPROVE with minor suggestions - Fix is correct and complete Phase 4 Fix: Analysis-based selection - PR's fix is optimal with minor improvements recommended Phase 4: Expand state file for Fix and Report phases Phase 3 Gate: PASSED - Line 165 bug fixed, tests verified Phase 2 Tests: Verify tests exist and compile successfully Phase 1 Pre-Flight: Document PR context and prior review findings
# PR Changes - MacCatalyst Picker Improvements Fixes #30897 Fixes #30891 ## Overview Improved MacCatalyst Picker implementation with proper focus management ## Changes Made ### 1. **PickerHandler.iOS.cs** - MacCatalyst-specific improvements #### Added UIAlertController instance field - Declared `UIAlertController? pickerController` as an instance field to enable proper dismissal via `Unfocus` command - Allows external code to programmatically close the picker dialog #### Improved picker dismiss logic - Moved picker dismiss logic from event handler to the "Done" button action - Removed `EditingDidEnd` event handler that was causing duplicate dismiss calls - Simplified focus state management by handling it directly in the Done action #### Added MapUnfocus command handler - Implemented `MapUnfocus` method for MacCatalyst to programmatically dismiss the picker - Properly updates `IsFocused` and `IsOpen` states when dismissed - Includes null checks for safety ### 2. **PickerHandler.cs** - Command mapper registration #### Registered Unfocus command for MacCatalyst - Added `#elif MACCATALYST` section to CommandMapper - Registered `nameof(IPicker.Unfocus)` command to enable programmatic picker dismissal on MacCatalyst - Brings MacCatalyst picker behavior in line with Android implementation ## Testing Issue2339 ## Platforms Affected - **MacCatalyst** (primary) - iOS (no behavior changes, shared code) ## Breaking Changes None - this is purely an implementation improvement with no API changes.
# PR Changes - MacCatalyst Picker Improvements Fixes #30897 Fixes #30891 ## Overview Improved MacCatalyst Picker implementation with proper focus management ## Changes Made ### 1. **PickerHandler.iOS.cs** - MacCatalyst-specific improvements #### Added UIAlertController instance field - Declared `UIAlertController? pickerController` as an instance field to enable proper dismissal via `Unfocus` command - Allows external code to programmatically close the picker dialog #### Improved picker dismiss logic - Moved picker dismiss logic from event handler to the "Done" button action - Removed `EditingDidEnd` event handler that was causing duplicate dismiss calls - Simplified focus state management by handling it directly in the Done action #### Added MapUnfocus command handler - Implemented `MapUnfocus` method for MacCatalyst to programmatically dismiss the picker - Properly updates `IsFocused` and `IsOpen` states when dismissed - Includes null checks for safety ### 2. **PickerHandler.cs** - Command mapper registration #### Registered Unfocus command for MacCatalyst - Added `#elif MACCATALYST` section to CommandMapper - Registered `nameof(IPicker.Unfocus)` command to enable programmatic picker dismissal on MacCatalyst - Brings MacCatalyst picker behavior in line with Android implementation ## Testing Issue2339 ## Platforms Affected - **MacCatalyst** (primary) - iOS (no behavior changes, shared code) ## Breaking Changes None - this is purely an implementation improvement with no API changes.
# PR Changes - MacCatalyst Picker Improvements Fixes #30897 Fixes #30891 ## Overview Improved MacCatalyst Picker implementation with proper focus management ## Changes Made ### 1. **PickerHandler.iOS.cs** - MacCatalyst-specific improvements #### Added UIAlertController instance field - Declared `UIAlertController? pickerController` as an instance field to enable proper dismissal via `Unfocus` command - Allows external code to programmatically close the picker dialog #### Improved picker dismiss logic - Moved picker dismiss logic from event handler to the "Done" button action - Removed `EditingDidEnd` event handler that was causing duplicate dismiss calls - Simplified focus state management by handling it directly in the Done action #### Added MapUnfocus command handler - Implemented `MapUnfocus` method for MacCatalyst to programmatically dismiss the picker - Properly updates `IsFocused` and `IsOpen` states when dismissed - Includes null checks for safety ### 2. **PickerHandler.cs** - Command mapper registration #### Registered Unfocus command for MacCatalyst - Added `#elif MACCATALYST` section to CommandMapper - Registered `nameof(IPicker.Unfocus)` command to enable programmatic picker dismissal on MacCatalyst - Brings MacCatalyst picker behavior in line with Android implementation ## Testing Issue2339 ## Platforms Affected - **MacCatalyst** (primary) - iOS (no behavior changes, shared code) ## Breaking Changes None - this is purely an implementation improvement with no API changes.
# PR Changes - MacCatalyst Picker Improvements Fixes #30897 Fixes #30891 ## Overview Improved MacCatalyst Picker implementation with proper focus management ## Changes Made ### 1. **PickerHandler.iOS.cs** - MacCatalyst-specific improvements #### Added UIAlertController instance field - Declared `UIAlertController? pickerController` as an instance field to enable proper dismissal via `Unfocus` command - Allows external code to programmatically close the picker dialog #### Improved picker dismiss logic - Moved picker dismiss logic from event handler to the "Done" button action - Removed `EditingDidEnd` event handler that was causing duplicate dismiss calls - Simplified focus state management by handling it directly in the Done action #### Added MapUnfocus command handler - Implemented `MapUnfocus` method for MacCatalyst to programmatically dismiss the picker - Properly updates `IsFocused` and `IsOpen` states when dismissed - Includes null checks for safety ### 2. **PickerHandler.cs** - Command mapper registration #### Registered Unfocus command for MacCatalyst - Added `#elif MACCATALYST` section to CommandMapper - Registered `nameof(IPicker.Unfocus)` command to enable programmatic picker dismissal on MacCatalyst - Brings MacCatalyst picker behavior in line with Android implementation ## Testing Issue2339 ## Platforms Affected - **MacCatalyst** (primary) - iOS (no behavior changes, shared code) ## Breaking Changes None - this is purely an implementation improvement with no API changes.
# PR Changes - MacCatalyst Picker Improvements Fixes #30897 Fixes #30891 ## Overview Improved MacCatalyst Picker implementation with proper focus management ## Changes Made ### 1. **PickerHandler.iOS.cs** - MacCatalyst-specific improvements #### Added UIAlertController instance field - Declared `UIAlertController? pickerController` as an instance field to enable proper dismissal via `Unfocus` command - Allows external code to programmatically close the picker dialog #### Improved picker dismiss logic - Moved picker dismiss logic from event handler to the "Done" button action - Removed `EditingDidEnd` event handler that was causing duplicate dismiss calls - Simplified focus state management by handling it directly in the Done action #### Added MapUnfocus command handler - Implemented `MapUnfocus` method for MacCatalyst to programmatically dismiss the picker - Properly updates `IsFocused` and `IsOpen` states when dismissed - Includes null checks for safety ### 2. **PickerHandler.cs** - Command mapper registration #### Registered Unfocus command for MacCatalyst - Added `#elif MACCATALYST` section to CommandMapper - Registered `nameof(IPicker.Unfocus)` command to enable programmatic picker dismissal on MacCatalyst - Brings MacCatalyst picker behavior in line with Android implementation ## Testing Issue2339 ## Platforms Affected - **MacCatalyst** (primary) - iOS (no behavior changes, shared code) ## Breaking Changes None - this is purely an implementation improvement with no API changes.
# PR Changes - MacCatalyst Picker Improvements Fixes #30897 Fixes #30891 ## Overview Improved MacCatalyst Picker implementation with proper focus management ## Changes Made ### 1. **PickerHandler.iOS.cs** - MacCatalyst-specific improvements #### Added UIAlertController instance field - Declared `UIAlertController? pickerController` as an instance field to enable proper dismissal via `Unfocus` command - Allows external code to programmatically close the picker dialog #### Improved picker dismiss logic - Moved picker dismiss logic from event handler to the "Done" button action - Removed `EditingDidEnd` event handler that was causing duplicate dismiss calls - Simplified focus state management by handling it directly in the Done action #### Added MapUnfocus command handler - Implemented `MapUnfocus` method for MacCatalyst to programmatically dismiss the picker - Properly updates `IsFocused` and `IsOpen` states when dismissed - Includes null checks for safety ### 2. **PickerHandler.cs** - Command mapper registration #### Registered Unfocus command for MacCatalyst - Added `#elif MACCATALYST` section to CommandMapper - Registered `nameof(IPicker.Unfocus)` command to enable programmatic picker dismissal on MacCatalyst - Brings MacCatalyst picker behavior in line with Android implementation ## Testing Issue2339 ## Platforms Affected - **MacCatalyst** (primary) - iOS (no behavior changes, shared code) ## Breaking Changes None - this is purely an implementation improvement with no API changes.
# PR Changes - MacCatalyst Picker Improvements Fixes #30897 Fixes #30891 ## Overview Improved MacCatalyst Picker implementation with proper focus management ## Changes Made ### 1. **PickerHandler.iOS.cs** - MacCatalyst-specific improvements #### Added UIAlertController instance field - Declared `UIAlertController? pickerController` as an instance field to enable proper dismissal via `Unfocus` command - Allows external code to programmatically close the picker dialog #### Improved picker dismiss logic - Moved picker dismiss logic from event handler to the "Done" button action - Removed `EditingDidEnd` event handler that was causing duplicate dismiss calls - Simplified focus state management by handling it directly in the Done action #### Added MapUnfocus command handler - Implemented `MapUnfocus` method for MacCatalyst to programmatically dismiss the picker - Properly updates `IsFocused` and `IsOpen` states when dismissed - Includes null checks for safety ### 2. **PickerHandler.cs** - Command mapper registration #### Registered Unfocus command for MacCatalyst - Added `#elif MACCATALYST` section to CommandMapper - Registered `nameof(IPicker.Unfocus)` command to enable programmatic picker dismissal on MacCatalyst - Brings MacCatalyst picker behavior in line with Android implementation ## Testing Issue2339 ## Platforms Affected - **MacCatalyst** (primary) - iOS (no behavior changes, shared code) ## Breaking Changes None - this is purely an implementation improvement with no API changes.
# PR Changes - MacCatalyst Picker Improvements Fixes #30897 Fixes #30891 ## Overview Improved MacCatalyst Picker implementation with proper focus management ## Changes Made ### 1. **PickerHandler.iOS.cs** - MacCatalyst-specific improvements #### Added UIAlertController instance field - Declared `UIAlertController? pickerController` as an instance field to enable proper dismissal via `Unfocus` command - Allows external code to programmatically close the picker dialog #### Improved picker dismiss logic - Moved picker dismiss logic from event handler to the "Done" button action - Removed `EditingDidEnd` event handler that was causing duplicate dismiss calls - Simplified focus state management by handling it directly in the Done action #### Added MapUnfocus command handler - Implemented `MapUnfocus` method for MacCatalyst to programmatically dismiss the picker - Properly updates `IsFocused` and `IsOpen` states when dismissed - Includes null checks for safety ### 2. **PickerHandler.cs** - Command mapper registration #### Registered Unfocus command for MacCatalyst - Added `#elif MACCATALYST` section to CommandMapper - Registered `nameof(IPicker.Unfocus)` command to enable programmatic picker dismissal on MacCatalyst - Brings MacCatalyst picker behavior in line with Android implementation ## Testing Issue2339 ## Platforms Affected - **MacCatalyst** (primary) - iOS (no behavior changes, shared code) ## Breaking Changes None - this is purely an implementation improvement with no API changes.
.NET MAUI inflight/candidate introduces significant improvements across all platforms with focus on quality, performance, and developer experience. This release includes 20 commits with various improvements, bug fixes, and enhancements. ## Blazor - Fix for BlazorWebView Back Navigation Issues on Android 13+ After Predictive Back Gesture Changes by @SuthiYuvaraj in #33213 <details> <summary>🔧 Fixes</summary> - [Back navigation different between .net 9 and .net 10 blazor hybrid](#32767) </details> ## CollectionView - [Android] Fix for CollectionView.EmptyView does not remeasure its height when the parent layout changes dynamically, causing incorrect sizing. by @BagavathiPerumal in #33559 <details> <summary>🔧 Fixes</summary> - [`CollectionView.EmptyView` does not remeasure its height when the parent layout changes dynamically, causing incorrect sizing.](#33324) </details> - [Android] Fixed CollectionView reordering last item by @vitalii-vov in #17825 <details> <summary>🔧 Fixes</summary> - [Android app crashes when dragging into CollectionView](#17823) </details> ## DateTimePicker - [iOS] Fix VoiceOver focus not shifting to Picker/DatePicker/TimePicker popups by @kubaflo in #33152 <details> <summary>🔧 Fixes</summary> - [Voiceover does not automatically shift focus to the "Category" popup when it opens.: A11y_Developer balance version .NET 10_Project_ScreenReader](#30746) </details> ## Dialogalert - [iOS 26] Fix DisplayPromptAsync maxLength not enforced due to new multi-range delegate by @Shalini-Ashokan in #33616 <details> <summary>🔧 Fixes</summary> - [[iOS 26.1] DisplayPromptAsync ignores maxLength and does not respect RTL FlowDirection](#33549) </details> ## Flyout - [iOS] Shell: Account for SafeArea when positioning flyout footer by @kubaflo in #32891 <details> <summary>🔧 Fixes</summary> - [[IOS] Footer not displaying in iOS when StackOrientation.Horizontal is set on FlyoutFooter](#26395) </details> ## Fonts - Hide obsolete FontSize values from IDE autocomplete by @noiseonwires in #33694 ## Gestures - Android pan fixes by @BurningLights in #21547 <details> <summary>🔧 Fixes</summary> - [Flickering occurs while updating the width of ContentView through PanGestureRecognizer.](#20772) </details> ## Navigation - Shell: Add duplicate route validation for sibling elements by @SubhikshaSf4851 in #32296 <details> <summary>🔧 Fixes</summary> - [OnNavigatedTo is not called when navigating from a specific page](#14000) </details> ## Picker - Improved Unfocus support for Picker on Mac Catalyst by @kubaflo in #33127 <details> <summary>🔧 Fixes</summary> - [When using voiceover unable to access expanded list of project combo box: A11y_.NET maui_user can creat a tak_Screen reader](#30897) - [Task and Project controls are not accessible with keyboard:A11y_.NET maui_User can create a new task_Keyboard](#30891) </details> ## SafeArea - [iOS] SafeArea: Return Empty for non-ISafeAreaView views (opt-in model) by @praveenkumarkarunanithi in #33526 <details> <summary>🔧 Fixes</summary> - [[iOS] SafeArea is not applied when a ContentPage uses a ControlTemplate](#33458) </details> ## Shell - [iOS] Fix ObjectDisposedException in TraitCollectionDidChange on window disposal by @jeremy-visionaid in #33353 <details> <summary>🔧 Fixes</summary> - [Intermittent crash on exit on MacCatalyst - ObjectDisposedException](#33352) </details> - [Issue-Resolver] Explicit fallback for BackButtonBehavior lookup by @kubaflo in #33204 <details> <summary>🔧 Fixes</summary> - [Setting BackButtonBehavior to not visible or not enabled does not work](#28570) - [BackButtonBehavior not bound](#33139) </details> ## Templates - [Templates] Remove redundant SemanticProperties.Description attribute by @kubaflo in #33621 <details> <summary>🔧 Fixes</summary> - [Task and Project controls are not accessible with keyboard:A11y_.NET maui_User can create a new task_Keyboard](#30891) - [Unable to select "Tags" when Voiceover is turned on.: A11y_Developer balance version .NET 10_Project_ScreenReader](#30749) </details> ## Theme - [Windows] Fix runtime theme update for controls and TitleBar by @Tamilarasan-Paranthaman in #31714 <details> <summary>🔧 Fixes</summary> - [[Windows][MacOS?] Change title bar color when switching light/dark theme at runtime](#12507) - [OS system components ignore app theme](#22058) - [[Mac Catalyst][Windows] TitleBar not reacting on UserAppTheme changes](#30518) - [In dark theme "Back" and "hamburger" button icon color contrast with background color is less than 3:1: A11y_.NET maui_User can get all the insights of Dashboard_Non text Contrast](#30807) - [`Switch` is invisible on `PointOver` when theme has changed](#31819) </details> ## Theming - [XSG] Fix Style Setters referencing source-generated bindable properties by @simonrozsival in #33562 ## Titlebar - [Windows] Fix TitleBar.IsVisible = false the caption buttons become unresponsive by @devanathan-vaithiyanathan in #33256 <details> <summary>🔧 Fixes</summary> - [When TitleBar.IsVisible = false the caption buttons become unresponsive on Windows](#33171) </details> ## WebView - Fix WebView JavaScript string escaping for backslashes and quotes by @StephaneDelcroix in #33726 ## Xaml - [XSG] Fix NaN value in XAML generating invalid code by @StephaneDelcroix in #33533 <details> <summary>🔧 Fixes</summary> - [[XSG] NaN value in XAML generates invalid code](#33532) </details> <details> <summary>📦 Other (1)</summary> - Remove InternalsVisibleTo attributes for .NET MAUI Community Toolkit by @jfversluis via @Copilot in #33442 </details> **Full Changelog**: main...inflight/candidate
PR Changes - MacCatalyst Picker Improvements
Fixes #30897
Fixes #30891
Overview
Improved MacCatalyst Picker implementation with proper focus management
Changes Made
1. PickerHandler.iOS.cs - MacCatalyst-specific improvements
Added UIAlertController instance field
UIAlertController? pickerControlleras an instance field to enable proper dismissal viaUnfocuscommandImproved picker dismiss logic
EditingDidEndevent handler that was causing duplicate dismiss callsAdded MapUnfocus command handler
MapUnfocusmethod for MacCatalyst to programmatically dismiss the pickerIsFocusedandIsOpenstates when dismissed2. PickerHandler.cs - Command mapper registration
Registered Unfocus command for MacCatalyst
#elif MACCATALYSTsection to CommandMappernameof(IPicker.Unfocus)command to enable programmatic picker dismissal on MacCatalystTesting
Issue2339
Platforms Affected
Breaking Changes
None - this is purely an implementation improvement with no API changes.