-
Notifications
You must be signed in to change notification settings - Fork 1.9k
[Mac] Fix for preventing macOS picker dialog from closing immediately when opened with Tab #33784
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| namespace Maui.Controls.Sample.Issues; | ||
|
|
||
| [Issue(IssueTracker.Github, 33463, "[macOS]Picker items are not visible", PlatformAffected.macOS)] | ||
| public class Issue33463 : TestContentPage | ||
| { | ||
| protected override void Init() | ||
| { | ||
| var picker = new Picker | ||
| { | ||
| AutomationId = "TestPicker", | ||
| Title = "Select an item" | ||
| }; | ||
| picker.Items.Add("Item 1"); | ||
| picker.Items.Add("Item 2"); | ||
| picker.Items.Add("Item 3"); | ||
|
|
||
| var entry = new Entry | ||
| { | ||
| AutomationId = "TestEntry", | ||
| Placeholder = "Entry for TAB focus" | ||
| }; | ||
|
|
||
| Content = new VerticalStackLayout | ||
| { | ||
| Padding = 12, | ||
| Spacing = 10, | ||
| Children = { picker, entry } | ||
| }; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| #if MACCATALYST // The reported scenario is specific to macOS, where the picker dialog closes automatically when opened using the Tab key, so this test is enabled only for macOS. | ||
| using NUnit.Framework; | ||
| using UITest.Appium; | ||
| using UITest.Core; | ||
|
|
||
| namespace Microsoft.Maui.TestCases.Tests.Issues; | ||
|
|
||
| public class Issue33463 : _IssuesUITest | ||
| { | ||
| public Issue33463(TestDevice testDevice) : base(testDevice) | ||
| { | ||
| } | ||
|
|
||
| public override string Issue => "[macOS]Picker items are not visible"; | ||
|
|
||
| [Test] | ||
| [Category(UITestCategories.Picker)] | ||
| public void PickerShouldRemainOpenWhenOpenedUsingTabKey() | ||
| { | ||
| App.WaitForElement("TestPicker"); | ||
|
|
||
| App.Tap("TestPicker"); | ||
| App.WaitForElement("Done"); | ||
| App.Tap("Done"); | ||
|
|
||
| App.SendTabKey(); | ||
| Task.Delay(800).Wait(); | ||
|
|
||
| var doneButton = App.FindElement("Done"); | ||
| Assert.That(doneButton, Is.Not.Null, | ||
| "The picker dialog should remain open when it is opened using the Tab key."); | ||
| } | ||
| } | ||
| #endif | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,6 +9,9 @@ public partial class PickerHandler : ViewHandler<IPicker, MauiPicker> | |
| { | ||
| readonly MauiPickerProxy _proxy = new(); | ||
| UIPickerView? _pickerView; | ||
| #if MACCATALYST | ||
| UIAlertController? _currentPickerController; | ||
| #endif | ||
|
|
||
| #if !MACCATALYST | ||
| protected override MauiPicker CreatePlatformView() | ||
|
|
@@ -59,7 +62,8 @@ void DisplayAlert(MauiPicker uITextField, int selectedIndex) | |
|
|
||
| // The UIPickerView is displayed as a subview of the UIAlertController when an empty string is provided as the title, instead of using the VirtualView title. | ||
| // This behavior deviates from the expected native macOS behavior. | ||
| var pickerController = UIAlertController.Create("", "", UIAlertControllerStyle.ActionSheet); | ||
| _currentPickerController = UIAlertController.Create("", "", UIAlertControllerStyle.ActionSheet); | ||
| var pickerController = _currentPickerController; | ||
|
Comment on lines
+65
to
+66
|
||
|
|
||
| // needs translation | ||
| pickerController.AddAction(UIAlertAction.Create("Done", | ||
|
|
@@ -84,11 +88,13 @@ void DisplayAlert(MauiPicker uITextField, int selectedIndex) | |
|
|
||
| EventHandler? editingDidEndHandler = null; | ||
|
|
||
| editingDidEndHandler = async (s, e) => | ||
| editingDidEndHandler = (s, e) => | ||
| { | ||
| await pickerController.DismissViewControllerAsync(true); | ||
| if (VirtualView is IPicker virtualView) | ||
| virtualView.IsFocused = virtualView.IsOpen = false; | ||
|
|
||
| _currentPickerController = null; | ||
|
|
||
| uITextField.EditingDidEnd -= editingDidEndHandler; | ||
| }; | ||
|
|
||
|
|
@@ -202,6 +208,32 @@ internal static void MapIsOpen(IPickerHandler handler, IPicker picker) | |
| handler.PlatformView?.UpdateIsOpen(picker); | ||
| } | ||
|
|
||
| #if MACCATALYST | ||
| internal static void MapFocus(IPickerHandler handler, IPicker picker, object? args) | ||
| { | ||
| if (handler.IsConnected() && handler is PickerHandler) | ||
| { | ||
| ViewHandler.MapFocus(handler, picker, args); | ||
| } | ||
| } | ||
|
|
||
| internal static void MapUnfocus(IPickerHandler handler, IPicker picker, object? args) | ||
| { | ||
| if (handler.IsConnected() && handler is PickerHandler pickerHandler) | ||
| { | ||
| // Dismiss the picker controller when Unfocus() is explicitly called | ||
| if (pickerHandler._currentPickerController != null) | ||
| { | ||
| var controller = pickerHandler._currentPickerController; | ||
| pickerHandler._currentPickerController = null; | ||
| controller.DismissViewController(true, null); | ||
| } | ||
|
|
||
| ViewHandler.MapUnfocus(handler, picker, args); | ||
| } | ||
| } | ||
| #endif | ||
|
|
||
| void UpdatePickerFromPickerSource(PickerSource? pickerSource) | ||
| { | ||
| if (VirtualView == null || PlatformView == null || pickerSource == null) | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After SendTabKey(), the test should verify that the picker opens before checking for the Done button. Currently, it relies on a fixed delay and then uses FindElement which may return null without waiting. If the picker hasn't opened yet, FindElement("Done") will fail.
The test should use WaitForElement instead of Task.Delay + FindElement:
This ensures the test waits for the picker to open rather than assuming 800ms is sufficient.