Skip to content
This repository has been archived by the owner on May 1, 2024. It is now read-only.

[iOS] Allow empty format in DatePicker #14695

Merged
merged 4 commits into from
Oct 11, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@
<Compile Include="_10337CustomRenderer.cs" />
<Compile Include="_11132CustomRenderer.cs" />
<Compile Include="CustomRenderers\_12372CustomRenderer.cs" />
<Compile Include="_13577CustomRenderer.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Xamarin.Forms.Controls\Xamarin.Forms.Controls.csproj">
Expand Down
78 changes: 78 additions & 0 deletions Xamarin.Forms.ControlGallery.iOS/_13577CustomRenderer.cs
Original file line number Diff line number Diff line change
@@ -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<Xamarin.Forms.DatePicker> 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<UIBarButtonItem>();
foreach (var item in originalToolbar.Items)
{
newItems.Add(item);
}

newItems.Insert(0, clearButton);

originalToolbar.Items = newItems.ToArray();
originalToolbar.SetNeedsDisplay();
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8" ?>
<local:TestContentPage
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="Test 13577" xmlns:local="using:Xamarin.Forms.Controls"
xmlns:issues="using:Xamarin.Forms.Controls.Issues"
x:Class="Xamarin.Forms.Controls.Issues.Issue13577">
<StackLayout>
<Label
Padding="12"
BackgroundColor="Black"
TextColor="White"
Text="If you can clear the selected Date, the test has passed."/>
<issues:NullableDatePicker
Format="dd-MM-yyyy"
NullableDate="{Binding NullableDate}" />
</StackLayout>
</local:TestContentPage>
Original file line number Diff line number Diff line change
@@ -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 = " ";
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1788,6 +1788,7 @@
<Compile Include="$(MSBuildThisFileDirectory)FrameBackgroundIssue.xaml.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue14664.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue14192.xaml.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue13577.xaml.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue14505.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue14505-II.cs" />
</ItemGroup>
Expand Down Expand Up @@ -2255,6 +2256,9 @@
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Issue14192.xaml">
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
</EmbeddedResource>
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Issue13577.xaml">
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Bugzilla27417Xaml.xaml">
Expand Down
9 changes: 5 additions & 4 deletions Xamarin.Forms.Platform.iOS/Renderers/DatePickerRenderer.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using System;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using Foundation;
using UIKit;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
Expand Down Expand Up @@ -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)
{
Expand Down