-
-
Save jrgcubano/4fdd6ec776c6ddeacb4d518b0355dd77 to your computer and use it in GitHub Desktop.
using UIKit; | |
using Xamarin.Forms; | |
namespace Check.iOS.Extensions | |
{ | |
/// <summary> | |
/// Color extensions | |
/// </summary> | |
public static class CheckColorExtensions | |
{ | |
internal static readonly UIColor SeventyPercentGrey = new UIColor(0.7f, 0.7f, 0.7f, 1); | |
public static bool IsDefault(this Color color) => Color.Default == color; | |
} | |
} |
// Example usage | |
<controls:ExtendedDatePicker | |
x:Name="ContactBirthDate" | |
Placeholder="{i18n:Translate Contact_BirthdayLabel}" | |
NullableDate="{Binding Contact.BirthDate}" | |
Format="d MMM yyyy" | |
XAlign="Start" | |
HasBorder="false" | |
HorizontalOptions="FillAndExpand" | |
StyleId="BirthDateFieldId" | |
VerticalOptions="Center" | |
IsEnabled="{Binding IsNotBusy}" > | |
</controls:ExtendedDatePicker> |
using System; | |
using Xamarin.Forms; | |
namespace Check.Client.Core.Controls | |
{ | |
/// <summary> | |
/// Extended DatePicker for Nullable Values | |
/// Via: https://forums.xamarin.com/discussion/20028/datepicker-possible-to-bind-to-nullable-date-value | |
/// Via: https://github.com/XLabs/Xamarin-Forms-Labs/wiki/ExtendedEntry | |
/// </summary> | |
public class ExtendedDatePicker : DatePicker | |
{ | |
/// <summary> | |
/// The font property | |
/// </summary> | |
public static readonly BindableProperty FontProperty = | |
BindableProperty.Create("Font", typeof(Font), typeof(ExtendedDatePicker), new Font()); | |
/// <summary> | |
/// The NullableDate property | |
/// </summary> | |
public static readonly BindableProperty NullableDateProperty = | |
BindableProperty.Create("NullableDate", typeof (DateTime?), typeof (ExtendedDatePicker), null, BindingMode.TwoWay); | |
/// <summary> | |
/// The XAlign property | |
/// </summary> | |
public static readonly BindableProperty XAlignProperty = | |
BindableProperty.Create("XAlign", typeof(TextAlignment), typeof(ExtendedDatePicker), | |
TextAlignment.Start); | |
/// <summary> | |
/// The HasBorder property | |
/// </summary> | |
public static readonly BindableProperty HasBorderProperty = | |
BindableProperty.Create("HasBorder", typeof(bool), typeof(ExtendedDatePicker), true); | |
/// <summary> | |
/// The Placeholder property | |
/// </summary> | |
public static readonly BindableProperty PlaceholderProperty = | |
BindableProperty.Create("Placeholder", typeof (string), typeof (ExtendedDatePicker), string.Empty, BindingMode.OneWay); | |
/// <summary> | |
/// The PlaceholderTextColor property | |
/// </summary> | |
public static readonly BindableProperty PlaceholderTextColorProperty = | |
BindableProperty.Create("PlaceholderTextColor", typeof(Color), typeof(ExtendedDatePicker), Color.Default); | |
/// <summary> | |
/// Gets or sets the Font | |
/// </summary> | |
public Font Font | |
{ | |
get { return (Font)GetValue(FontProperty); } | |
set { SetValue(FontProperty, value); } | |
} | |
/// <summary> | |
/// Get or sets the NullableDate | |
/// </summary> | |
public DateTime? NullableDate | |
{ | |
get { return (DateTime?) GetValue(NullableDateProperty); } | |
set | |
{ | |
if (value != NullableDate) | |
{ | |
SetValue(NullableDateProperty, value); | |
UpdateDate(); | |
} | |
} | |
} | |
/// <summary> | |
/// Gets or sets the X alignment of the text | |
/// </summary> | |
public TextAlignment XAlign | |
{ | |
get { return (TextAlignment)GetValue(XAlignProperty); } | |
set { SetValue(XAlignProperty, value); } | |
} | |
/// <summary> | |
/// Gets or sets if the border should be shown or not | |
/// </summary> | |
public bool HasBorder | |
{ | |
get { return (bool)GetValue(HasBorderProperty); } | |
set { SetValue(HasBorderProperty, value); } | |
} | |
/// <summary> | |
/// Get or sets the PlaceHolder | |
/// </summary> | |
public string Placeholder | |
{ | |
get { return (string) GetValue(PlaceholderProperty); } | |
set { SetValue(PlaceholderProperty, value); } | |
} | |
/// <summary> | |
/// Sets color for placeholder text | |
/// </summary> | |
public Color PlaceholderTextColor | |
{ | |
get { return (Color)GetValue(PlaceholderTextColorProperty); } | |
set { SetValue(PlaceholderTextColorProperty, value); } | |
} | |
protected override void OnBindingContextChanged() | |
{ | |
base.OnBindingContextChanged(); | |
UpdateDate(); | |
} | |
protected override void OnPropertyChanged(string propertyName = null) | |
{ | |
base.OnPropertyChanged(propertyName); | |
//Device.OnPlatform(() => | |
//{ | |
if (propertyName == IsFocusedProperty.PropertyName) | |
{ | |
if (IsFocused) | |
{ | |
if (!NullableDate.HasValue) | |
{ | |
Date = (DateTime) DateProperty.DefaultValue; | |
} | |
} | |
else | |
{ | |
OnPropertyChanged(DateProperty.PropertyName); | |
} | |
} | |
//}); | |
if (propertyName == DateProperty.PropertyName) | |
{ | |
NullableDate = Date; | |
} | |
if (propertyName == NullableDateProperty.PropertyName) | |
{ | |
if (NullableDate.HasValue) | |
{ | |
Date = NullableDate.Value; | |
} | |
} | |
} | |
private void UpdateDate() | |
{ | |
if (NullableDate.HasValue) | |
{ | |
Date = NullableDate.Value; | |
} | |
else | |
{ | |
Date = (DateTime)DateProperty.DefaultValue; | |
} | |
} | |
} | |
} |
using Android.Views; | |
using Check.Client.Core.Controls; | |
using Check.Droid.Renderers; | |
using System.ComponentModel; | |
using Xamarin.Forms; | |
using Xamarin.Forms.Platform.Android; | |
[assembly: ExportRenderer(typeof(ExtendedDatePicker), typeof(ExtendedDatePickerRenderer))] | |
namespace Check.Droid.Renderers | |
{ | |
/// <summary> | |
/// Extended DatePicker Renderer for Nullable Values | |
/// Via: https://forums.xamarin.com/discussion/20028/datepicker-possible-to-bind-to-nullable-date-value | |
/// Via: https://github.com/XLabs/Xamarin-Forms-Labs/wiki/ExtendedEntry | |
/// </summary> | |
public class ExtendedDatePickerRenderer : DatePickerRenderer | |
{ | |
protected override void OnElementChanged(ElementChangedEventArgs<DatePicker> e) | |
{ | |
base.OnElementChanged(e); | |
var view = Element as ExtendedDatePicker; | |
if (view != null) | |
{ | |
SetFont(view); | |
SetTextAlignment(view); | |
// SetBorder(view); | |
SetNullableText(view); | |
SetPlaceholder(view); | |
SetPlaceholderTextColor(view); | |
} | |
} | |
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e) | |
{ | |
base.OnElementPropertyChanged(sender, e); | |
var view = (ExtendedDatePicker)Element; | |
if (e.PropertyName == ExtendedDatePicker.FontProperty.PropertyName) | |
SetFont(view); | |
else if (e.PropertyName == ExtendedDatePicker.XAlignProperty.PropertyName) | |
SetTextAlignment(view); | |
// else if (e.PropertyName == ExtendedDatePicker.HasBorderProperty.PropertyName) | |
// SetBorder(view); | |
else if (e.PropertyName == ExtendedDatePicker.NullableDateProperty.PropertyName) | |
SetNullableText(view); | |
else if (e.PropertyName == ExtendedDatePicker.PlaceholderProperty.PropertyName) | |
SetPlaceholder(view); | |
else if (e.PropertyName == ExtendedDatePicker.PlaceholderTextColorProperty.PropertyName) | |
SetPlaceholderTextColor(view); | |
} | |
/// <summary> | |
/// Sets the text alignment. | |
/// </summary> | |
/// <param name="view">The view.</param> | |
private void SetTextAlignment(ExtendedDatePicker view) | |
{ | |
switch (view.XAlign) | |
{ | |
case Xamarin.Forms.TextAlignment.Center: | |
Control.Gravity = GravityFlags.CenterHorizontal; | |
break; | |
case Xamarin.Forms.TextAlignment.End: | |
Control.Gravity = GravityFlags.End; | |
break; | |
case Xamarin.Forms.TextAlignment.Start: | |
Control.Gravity = GravityFlags.Start; | |
break; | |
} | |
} | |
/// <summary> | |
/// Sets the font. | |
/// </summary> | |
/// <param name="view">The view.</param> | |
private void SetFont(ExtendedDatePicker view) | |
{ | |
if (view.Font != Font.Default) | |
{ | |
Control.TextSize = view.Font.ToScaledPixel(); | |
Control.Typeface = view.Font.ToExtendedTypeface(Context); | |
} | |
} | |
/// <summary> | |
/// Set text based on nullable value | |
/// </summary> | |
/// <param name="view"></param> | |
private void SetNullableText(ExtendedDatePicker view) | |
{ | |
if (view.NullableDate == null) | |
Control.Text = string.Empty; | |
} | |
/// <summary> | |
/// Set the placeholder | |
/// </summary> | |
/// <param name="view"></param> | |
private void SetPlaceholder(ExtendedDatePicker view) | |
{ | |
Control.Hint = view.Placeholder; | |
} | |
/// <summary> | |
/// Sets the color of the placeholder text. | |
/// </summary> | |
/// <param name="view">The view.</param> | |
private void SetPlaceholderTextColor(ExtendedDatePicker view) | |
{ | |
if (view.PlaceholderTextColor != Color.Default) | |
{ | |
Control.SetHintTextColor(view.PlaceholderTextColor.ToAndroid()); | |
} | |
} | |
} | |
} |
using Xamarin.Forms.Platform.iOS; | |
using Xamarin.Forms; | |
using Check.Client.Core.Controls; | |
using System.ComponentModel; | |
using UIKit; | |
using Check.iOS.Renderers; | |
using Check.iOS.Extensions; | |
using Foundation; | |
using System; | |
using CoreGraphics; | |
[assembly: ExportRenderer(typeof(ExtendedDatePicker), typeof(ExtendedDatePickerRenderer))] | |
namespace Check.iOS.Renderers | |
{ | |
/// <summary> | |
/// Extended DatePicker Renderer for Nullable Values | |
/// Via: https://forums.xamarin.com/discussion/20028/datepicker-possible-to-bind-to-nullable-date-value | |
/// Via: https://github.com/XLabs/Xamarin-Forms-Labs/wiki/ExtendedEntry | |
/// </summary> | |
public class ExtendedDatePickerRenderer : DatePickerRenderer | |
{ | |
protected override void OnElementChanged(ElementChangedEventArgs<DatePicker> e) | |
{ | |
base.OnElementChanged(e); | |
var view = Element as ExtendedDatePicker; | |
if (view != null) | |
{ | |
SetFont(view); | |
SetTextAlignment(view); | |
SetBorder(view); | |
SetNullableText(view); | |
SetPlaceholderTextColor(view); | |
ResizeHeight(); | |
} | |
} | |
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e) | |
{ | |
base.OnElementPropertyChanged(sender, e); | |
var view = (ExtendedDatePicker)Element; | |
if (e.PropertyName == ExtendedDatePicker.FontProperty.PropertyName) | |
SetFont(view); | |
else if (e.PropertyName == ExtendedDatePicker.XAlignProperty.PropertyName) | |
SetTextAlignment(view); | |
else if (e.PropertyName == ExtendedDatePicker.HasBorderProperty.PropertyName) | |
SetBorder(view); | |
else if (e.PropertyName == ExtendedDatePicker.NullableDateProperty.PropertyName) | |
SetNullableText(view); | |
else if (e.PropertyName == ExtendedDatePicker.PlaceholderTextColorProperty.PropertyName) | |
SetPlaceholderTextColor(view); | |
ResizeHeight(); | |
} | |
/// <summary> | |
/// Sets the text alignment. | |
/// </summary> | |
/// <param name="view">The view.</param> | |
private void SetTextAlignment(ExtendedDatePicker view) | |
{ | |
switch (view.XAlign) | |
{ | |
case TextAlignment.Center: | |
Control.TextAlignment = UITextAlignment.Center; | |
break; | |
case TextAlignment.End: | |
Control.TextAlignment = UITextAlignment.Right; | |
break; | |
case TextAlignment.Start: | |
Control.TextAlignment = UITextAlignment.Left; | |
break; | |
} | |
} | |
/// <summary> | |
/// Sets the font. | |
/// </summary> | |
/// <param name="view">The view.</param> | |
private void SetFont(ExtendedDatePicker view) | |
{ | |
UIFont uiFont; | |
if (view.Font != Font.Default && (uiFont = view.Font.ToUIFont()) != null) | |
Control.Font = uiFont; | |
else if (view.Font == Font.Default) | |
Control.Font = UIFont.SystemFontOfSize(17f); | |
} | |
/// <summary> | |
/// Sets the border. | |
/// </summary> | |
/// <param name="view">The view.</param> | |
private void SetBorder(ExtendedDatePicker view) | |
{ | |
Control.BorderStyle = view.HasBorder ? UITextBorderStyle.RoundedRect : UITextBorderStyle.None; | |
} | |
/// <summary> | |
/// Set text based on nullable value | |
/// </summary> | |
/// <param name="view"></param> | |
private void SetNullableText(ExtendedDatePicker view) | |
{ | |
if (view.NullableDate == null) | |
Control.Text = string.Empty; | |
} | |
/// <summary> | |
/// Resizes the height. | |
/// </summary> | |
private void ResizeHeight() | |
{ | |
if (Element.HeightRequest >= 0) return; | |
var height = Math.Max(Bounds.Height, | |
new UITextField { Font = Control.Font }.IntrinsicContentSize.Height) * 2; | |
Control.Frame = new CGRect(0.0f, 0.0f, (nfloat)Element.Width, (nfloat)height); | |
Element.HeightRequest = height; | |
} | |
/// <summary> | |
/// Sets the color of the placeholder text. | |
/// </summary> | |
/// <param name="view">The view.</param> | |
private void SetPlaceholderTextColor(ExtendedDatePicker view) | |
{ | |
if (!string.IsNullOrEmpty(view.Placeholder)) | |
{ | |
var foregroundUIColor = view.PlaceholderTextColor.ToUIColor(CheckColorExtensions.SeventyPercentGrey); | |
var backgroundUIColor = view.BackgroundColor.ToUIColor(); | |
var targetFont = Control.Font; | |
Control.AttributedPlaceholder = new NSAttributedString(view.Placeholder, targetFont, foregroundUIColor, backgroundUIColor); | |
} | |
} | |
} | |
} |
is this the correct line in content?
xmlns:controls="clr-namespace:MyApp;assembly=MyApp"
EDIT: In my case that was correct. However the date is still rendered in the date field and not the string placed in the placeholder property, while debuggin I can see that the Control.Hint is set correctly with the passed string, but still not showing the placeholder.
Any ideas?
How can I implement Cancel and OK events for both IOS and Androip. Thanks.
Anyone interested in UWP could look at this issue on a project featuring iOS and Android renderers. Here I outline an approach for a 'right-click' to clear behaviour. Not perfect but it might help someone:
Does anyone ever use this Control? I have a fundamental issue with it and nobody else seems to have that problem.
In ExtendedDatePicker OnBindingContextChanged UpdateDate is called.
protected override void OnBindingContextChanged()
{
base.OnBindingContextChanged();
UpdateDate();
}
UpdateDate checks the NullableDate property and if that is Null it updates the underlying DatePicker's Date property to min date of 01/01/1900.
private void UpdateDate()
{
if (NullableDate.HasValue)
{
Date = NullableDate.Value;
}
else
{
Date = (DateTime)DateProperty.DefaultValue;
}
}
Setting of the Date property triggers an OnPropertyChnaged in ExtendedDatePicker that then sets the NullableDate to the newly updated Date of 01/01/1900 therefore removing the null Date!
if (propertyName == DateProperty.PropertyName)
{
NullableDate = Date;
}
This means you never have a NullableDate that is Null after the first pass of the Binding code. Surely other people have seen this issue too
I have same issue as AhmmedTowfique, how do we fix this?
EDIT: Install XLabs