diff --git a/Xamarin.Forms.ControlGallery.iOS/Xamarin.Forms.ControlGallery.iOS.csproj b/Xamarin.Forms.ControlGallery.iOS/Xamarin.Forms.ControlGallery.iOS.csproj index e69d017231c..2932fd8185f 100644 --- a/Xamarin.Forms.ControlGallery.iOS/Xamarin.Forms.ControlGallery.iOS.csproj +++ b/Xamarin.Forms.ControlGallery.iOS/Xamarin.Forms.ControlGallery.iOS.csproj @@ -5,7 +5,7 @@ Debug iPhone - $(iOSPlatform) + iPhoneSimulator {C7131F14-274F-4B55-ACA9-E81731AD012F} {FEACFBD2-3405-455C-9665-78FE426C6842};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} Exe @@ -146,6 +146,7 @@ + diff --git a/Xamarin.Forms.ControlGallery.iOS/_13577CustomRenderer.cs b/Xamarin.Forms.ControlGallery.iOS/_13577CustomRenderer.cs new file mode 100644 index 00000000000..d5c40f4c7ea --- /dev/null +++ b/Xamarin.Forms.ControlGallery.iOS/_13577CustomRenderer.cs @@ -0,0 +1,78 @@ +using System; +using System.Collections.Generic; +using CoreGraphics; +using UIKit; +using Xamarin.Forms; +using Xamarin.Forms.ControlGallery.iOS; +using Xamarin.Forms.Controls.Issues; +using Xamarin.Forms.Platform.iOS; + +[assembly: ExportRenderer(typeof(NullableDatePicker), typeof(_13577CustomRenderer))] +namespace Xamarin.Forms.ControlGallery.iOS +{ + public class _13577CustomRenderer : DatePickerRenderer + { + public NullableDatePicker Entry => Element as NullableDatePicker; + + protected override void OnElementChanged(ElementChangedEventArgs e) + { + base.OnElementChanged(e); + + if (Control != null) + { + AddClearButton(); + + // Border style; Remove corner radius and change colors + Control.BorderStyle = UITextBorderStyle.Line; + Control.Layer.CornerRadius = 0; + Control.Layer.BorderWidth = 1; + + // Add padding + Control.LeftView = new UIView(new CGRect(0, 0, 10, 0)); + Control.LeftViewMode = UITextFieldViewMode.Always; + Control.RightView = new UIView(new CGRect(0, 0, 10, 0)); + Control.RightViewMode = UITextFieldViewMode.Always; + + if (e.NewElement != null) + { + try + { + if (UIDevice.CurrentDevice.CheckSystemVersion(14, 0)) + { + UIDatePicker picker = (UIDatePicker)Control.InputView; + picker.PreferredDatePickerStyle = UIDatePickerStyle.Wheels; + } + } + catch (Exception) + { + // Do nothing + } + } + } + } + + private void AddClearButton() + { + if (Control.InputAccessoryView is UIToolbar originalToolbar && originalToolbar.Items.Length <= 2) + { + var clearButton = new UIBarButtonItem("Delete", UIBarButtonItemStyle.Plain, (sender, ev) => + { + NullableDatePicker baseDatePicker = this.Element as NullableDatePicker; + Element.Unfocus(); + baseDatePicker.CleanDate(); + }); + + var newItems = new List(); + foreach (var item in originalToolbar.Items) + { + newItems.Add(item); + } + + newItems.Insert(0, clearButton); + + originalToolbar.Items = newItems.ToArray(); + originalToolbar.SetNeedsDisplay(); + } + } + } +} \ No newline at end of file diff --git a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue13577.xaml b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue13577.xaml new file mode 100644 index 00000000000..30368443830 --- /dev/null +++ b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue13577.xaml @@ -0,0 +1,21 @@ + + + + + \ No newline at end of file diff --git a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue13577.xaml.cs b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue13577.xaml.cs new file mode 100644 index 00000000000..7208f5dee13 --- /dev/null +++ b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue13577.xaml.cs @@ -0,0 +1,126 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using Xamarin.Forms.CustomAttributes; +using Xamarin.Forms.Internals; + +#if UITEST +using Xamarin.UITest; +using NUnit.Framework; +using Xamarin.Forms.Core.UITests; +#endif + +namespace Xamarin.Forms.Controls.Issues +{ + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Github, 13577, + "[Bug][DatePicker][XF5] DatePicker empty format now invalid", + PlatformAffected.iOS)] + public partial class Issue13577 : TestContentPage + { + public Issue13577() + { +#if APP + InitializeComponent(); +#endif + } + + protected override void Init() + { + BindingContext = new Issue13577ViewModel(); + } + } + + public class Issue13577ViewModel + { + public Issue13577ViewModel() + { + NullableDate = null; + } + + public DateTime? NullableDate { get; set; } + } + + public class NullableDatePicker : Xamarin.Forms.DatePicker + { + public static readonly BindableProperty NullableDateProperty = BindableProperty.Create("NullableDate", typeof(DateTime?), typeof(NullableDatePicker), null, BindingMode.TwoWay); + + public DateTime? NullableDate + { + get + { + return (DateTime?)GetValue(NullableDateProperty); + } + set + { + if (value != NullableDate) + { + SetValue(NullableDateProperty, value); + UpdateDate(); + } + } + } + + public void CleanDate() + { + NullableDate = null; + UpdateDate(); + } + + public void AssignValue() + { + NullableDate = Date; + UpdateDate(); + } + + protected override void OnBindingContextChanged() + { + base.OnBindingContextChanged(); + UpdateDate(); + } + + protected override void OnPropertyChanged(string propertyName = null) + { + base.OnPropertyChanged(propertyName); + + if (propertyName == IsFocusedProperty.PropertyName) + { + if (!IsFocused) + { + OnPropertyChanged(DateProperty.PropertyName); + } + } + + if (propertyName == DateProperty.PropertyName) + { + NullableDate = Date; + } + + if (propertyName == NullableDateProperty.PropertyName) + { + if (NullableDate.HasValue) + { + Date = NullableDate.Value; + Format = "dd-MM-yyyy"; + } + else + { + Format = " "; + } + } + } + + private void UpdateDate() + { + if (NullableDate.HasValue) + { + Date = NullableDate.Value; + Format = "dd-MM-yyyy"; + } + else + { + Format = " "; + } + } + } +} \ No newline at end of file diff --git a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Xamarin.Forms.Controls.Issues.Shared.projitems b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Xamarin.Forms.Controls.Issues.Shared.projitems index 3cbfe8c87b7..a54f9759f4f 100644 --- a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Xamarin.Forms.Controls.Issues.Shared.projitems +++ b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Xamarin.Forms.Controls.Issues.Shared.projitems @@ -1786,6 +1786,7 @@ + @@ -2248,6 +2249,9 @@ MSBuild:UpdateDesignTimeXaml + + MSBuild:UpdateDesignTimeXaml + diff --git a/Xamarin.Forms.Platform.iOS/Renderers/DatePickerRenderer.cs b/Xamarin.Forms.Platform.iOS/Renderers/DatePickerRenderer.cs index 92351097bc5..9a0702eb956 100644 --- a/Xamarin.Forms.Platform.iOS/Renderers/DatePickerRenderer.cs +++ b/Xamarin.Forms.Platform.iOS/Renderers/DatePickerRenderer.cs @@ -1,7 +1,6 @@ using System; using System.ComponentModel; using System.Globalization; -using System.Linq; using Foundation; using UIKit; using Xamarin.Forms.PlatformConfiguration.iOSSpecific; @@ -169,10 +168,12 @@ void UpdateDateFromModel(bool animate) _picker.SetDate(Element.Date.ToNSDate(), animate); // Can't use Element.Format because it won't display the correct format if the region and language are set differently - if (string.IsNullOrWhiteSpace(Element.Format) || Element.Format.Equals("d") || Element.Format.Equals("D")) + if (Element.Format.Equals("d") || Element.Format.Equals("D")) { - NSDateFormatter dateFormatter = new NSDateFormatter(); - dateFormatter.TimeZone = NSTimeZone.FromGMT(0); + NSDateFormatter dateFormatter = new NSDateFormatter + { + TimeZone = NSTimeZone.FromGMT(0) + }; if (Element.Format?.Equals("D") == true) {