Skip to content

Commit f1298b4

Browse files
jsuarezruizmattleibowhartez
committed
Picker Handlers (#433)
* PickerHandlers * Nullability fixes * Updated Picker device tests * New things in the tests! * Removed unnecessary Android Api level validation * Added Picker Items null validation in iOS PickerHandler * Moved Picker Handler tests between different classes * Renamed NativePicker to MauiPicker * Removed unused code from iOS PickerExtensions * Fix build error * Fix build error * Remove duplicate class Co-authored-by: Matthew Leibowitz <[email protected]> Co-authored-by: E.Z. Hart <[email protected]>
1 parent b6f3c17 commit f1298b4

File tree

24 files changed

+799
-16
lines changed

24 files changed

+799
-16
lines changed

src/Compatibility/Core/src/Android/AppCompat/PickerRenderer.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ protected override void OnFocusChangeRequested(object sender, VisualElement.Focu
109109
}
110110
}
111111

112+
[PortHandler("Partially ported, still missing code related to TitleColor, etc.")]
112113
void IPickerRenderer.OnClick()
113114
{
114115
Picker model = Element;
@@ -168,6 +169,7 @@ protected void UpdateCharacterSpacing()
168169
}
169170
}
170171

172+
[PortHandler("Partially ported, still missing code related to TitleColor, etc.")]
171173
void UpdatePicker()
172174
{
173175
UpdatePlaceHolderText();

src/Compatibility/Core/src/iOS/Renderers/PickerRenderer.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
namespace Microsoft.Maui.Controls.Compatibility.Platform.iOS
1313
{
14+
[PortHandler]
1415
internal class ReadOnlyField : NoCaretField
1516
{
1617
readonly HashSet<string> enableActions;
@@ -32,6 +33,7 @@ public PickerRenderer()
3233

3334
}
3435

36+
[PortHandler]
3537
protected override UITextField CreateNativeControl()
3638
{
3739
return new ReadOnlyField { BorderStyle = UITextBorderStyle.RoundedRect };
@@ -56,6 +58,8 @@ public PickerRendererBase()
5658
}
5759

5860
protected abstract override TControl CreateNativeControl();
61+
62+
[PortHandler("Partially ported, still missing code related to TitleColor, etc.")]
5963
protected override void OnElementChanged(ElementChangedEventArgs<Picker> e)
6064
{
6165
if (e.OldElement != null)
@@ -231,6 +235,7 @@ protected internal virtual void UpdatePlaceholder()
231235
protected virtual void UpdateAttributedPlaceholder(NSAttributedString nsAttributedString) =>
232236
Control.AttributedPlaceholder = nsAttributedString;
233237

238+
[PortHandler]
234239
void UpdatePicker()
235240
{
236241
var selectedIndex = Element.SelectedIndex;
@@ -266,6 +271,7 @@ void UpdatePickerNativeSize(string oldText)
266271
((IVisualElementController)Element).NativeSizeChanged();
267272
}
268273

274+
[PortHandler]
269275
void UpdatePickerSelectedIndex(int formsIndex)
270276
{
271277
var source = (PickerSource)_picker.Model;
@@ -334,6 +340,7 @@ protected override void Dispose(bool disposing)
334340
base.Dispose(disposing);
335341
}
336342

343+
[PortHandler]
337344
class PickerSource : UIPickerViewModel
338345
{
339346
PickerRendererBase<TControl> _renderer;

src/Controls/samples/Controls.Sample/Pages/MainPage.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
using System;
2+
using System.Collections.Generic;
13
using Maui.Controls.Sample.ViewModel;
24
using Microsoft.Extensions.DependencyInjection;
35
using Microsoft.Maui;
@@ -113,6 +115,23 @@ void SetupMauiLayout()
113115
placeholderSearchBar.Placeholder = "Placeholder";
114116
verticalStack.Add(placeholderSearchBar);
115117

118+
119+
var monkeyList = new List<string>
120+
{
121+
"Baboon",
122+
"Capuchin Monkey",
123+
"Blue Monkey",
124+
"Squirrel Monkey",
125+
"Golden Lion Tamarin",
126+
"Howler Monkey",
127+
"Japanese Macaque"
128+
};
129+
130+
var picker = new Picker { Title = "Select a monkey" };
131+
132+
picker.ItemsSource = monkeyList;
133+
verticalStack.Add(picker);
134+
116135
verticalStack.Add(new Slider());
117136

118137
verticalStack.Add(new Stepper());
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
namespace Microsoft.Maui.Controls
2+
{
3+
public partial class Picker : IPicker
4+
{
5+
6+
}
7+
}

src/Controls/src/Core/Picker.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
namespace Microsoft.Maui.Controls
1111
{
12-
public class Picker : View, IFontElement, ITextElement, ITextAlignmentElement, IElementConfiguration<Picker>
12+
public partial class Picker : View, IFontElement, ITextElement, ITextAlignmentElement, IElementConfiguration<Picker>
1313
{
1414
public static readonly BindableProperty TextColorProperty = TextElement.TextColorProperty;
1515

src/Core/src/Core/IPicker.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
using System.Collections;
2+
using System.Collections.Generic;
3+
4+
namespace Microsoft.Maui
5+
{
6+
public interface IPicker : IView
7+
{
8+
string Title { get; }
9+
IList<string> Items { get; }
10+
IList ItemsSource { get; }
11+
int SelectedIndex { get; set; }
12+
object? SelectedItem { get; set; }
13+
}
14+
}
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
using System;
2+
using System.Collections.Specialized;
3+
using System.Linq;
4+
using Android.App;
5+
using AResource = Android.Resource;
6+
7+
namespace Microsoft.Maui.Handlers
8+
{
9+
public partial class PickerHandler : AbstractViewHandler<IPicker, MauiPicker>
10+
{
11+
AlertDialog? _dialog;
12+
13+
protected override MauiPicker CreateNativeView() =>
14+
new MauiPicker(Context);
15+
16+
protected override void ConnectHandler(MauiPicker nativeView)
17+
{
18+
nativeView.FocusChange += OnFocusChange;
19+
nativeView.Click += OnClick;
20+
21+
if (VirtualView != null && VirtualView.Items is INotifyCollectionChanged notifyCollection)
22+
notifyCollection.CollectionChanged += OnCollectionChanged;
23+
24+
base.ConnectHandler(nativeView);
25+
}
26+
27+
protected override void DisconnectHandler(MauiPicker nativeView)
28+
{
29+
nativeView.FocusChange -= OnFocusChange;
30+
nativeView.Click -= OnClick;
31+
32+
if (VirtualView != null && VirtualView.Items is INotifyCollectionChanged notifyCollection)
33+
notifyCollection.CollectionChanged -= OnCollectionChanged;
34+
35+
base.DisconnectHandler(nativeView);
36+
}
37+
public static void MapTitle(PickerHandler handler, IPicker picker)
38+
{
39+
handler.TypedNativeView?.UpdateTitle(picker);
40+
}
41+
42+
public static void MapSelectedIndex(PickerHandler handler, IPicker picker)
43+
{
44+
handler.TypedNativeView?.UpdateSelectedIndex(picker);
45+
}
46+
47+
void OnFocusChange(object? sender, global::Android.Views.View.FocusChangeEventArgs e)
48+
{
49+
if (TypedNativeView == null)
50+
return;
51+
52+
if (e.HasFocus)
53+
{
54+
if (TypedNativeView.Clickable)
55+
TypedNativeView.CallOnClick();
56+
else
57+
OnClick(TypedNativeView, EventArgs.Empty);
58+
}
59+
else if (_dialog != null)
60+
{
61+
_dialog.Hide();
62+
TypedNativeView.ClearFocus();
63+
_dialog = null;
64+
}
65+
}
66+
67+
void OnClick(object? sender, EventArgs e)
68+
{
69+
if (_dialog == null && VirtualView != null)
70+
{
71+
using (var builder = new AlertDialog.Builder(Context))
72+
{
73+
builder.SetTitle(VirtualView.Title ?? string.Empty);
74+
75+
string[] items = VirtualView.Items.ToArray();
76+
77+
builder.SetItems(items, (s, e) =>
78+
{
79+
var selectedIndex = e.Which;
80+
VirtualView.SelectedIndex = selectedIndex;
81+
TypedNativeView?.UpdatePicker(VirtualView);
82+
});
83+
84+
builder.SetNegativeButton(AResource.String.Cancel, (o, args) => { });
85+
86+
_dialog = builder.Create();
87+
}
88+
89+
if (_dialog == null)
90+
return;
91+
92+
_dialog.SetCanceledOnTouchOutside(true);
93+
94+
_dialog.DismissEvent += (sender, args) =>
95+
{
96+
_dialog.Dispose();
97+
_dialog = null;
98+
};
99+
100+
_dialog.Show();
101+
}
102+
}
103+
104+
void OnCollectionChanged(object? sender, EventArgs e)
105+
{
106+
if (VirtualView == null || TypedNativeView == null)
107+
return;
108+
109+
TypedNativeView.UpdatePicker(VirtualView);
110+
}
111+
}
112+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
using System;
2+
3+
namespace Microsoft.Maui.Handlers
4+
{
5+
public partial class PickerHandler : AbstractViewHandler<IPicker, object>
6+
{
7+
protected override object CreateNativeView() => throw new NotImplementedException();
8+
9+
public static void MapTitle(PickerHandler handler, IPicker view) { }
10+
public static void MapSelectedIndex(PickerHandler handler, IPicker view) { }
11+
}
12+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
namespace Microsoft.Maui.Handlers
2+
{
3+
public partial class PickerHandler
4+
{
5+
public static PropertyMapper<IPicker, PickerHandler> PickerMapper = new PropertyMapper<IPicker, PickerHandler>(ViewHandler.ViewMapper)
6+
{
7+
[nameof(IPicker.Title)] = MapTitle,
8+
[nameof(IPicker.SelectedIndex)] = MapSelectedIndex
9+
};
10+
11+
public PickerHandler() : base(PickerMapper)
12+
{
13+
14+
}
15+
16+
public PickerHandler(PropertyMapper mapper) : base(mapper)
17+
{
18+
19+
}
20+
}
21+
}

0 commit comments

Comments
 (0)