--- /dev/null
+using System.ComponentModel;
+using System.Linq;
+using Tizen.Xamarin.Forms.Extension;
+using Tizen.Xamarin.Forms.Extension.Renderer;
+using Xamarin.Forms.Platform.Tizen;
+using EDateTimeSelector = ElmSharp.DateTimeSelector;
+using TForms = Xamarin.Forms.Platform.Tizen.Forms;
+
+[assembly: ExportRenderer(typeof(DateTimeView), typeof(DateTimeViewRenderer))]
+
+namespace Tizen.Xamarin.Forms.Extension.Renderer
+{
+ public class DateTimeViewRenderer : ViewRenderer<DateTimeView, EDateTimeSelector>
+ {
+ static readonly string DateStyle = "date_layout";
+ static readonly string TimeStyle = "time_layout";
+
+ static readonly string[] UseDateFormat = { "%Y", "%m", "%b", "%B", "%h", "%d", "%e", "%c", "%x", "%F" };
+ static readonly string[] UseTimeFormat = { "%I", "%H", "%k", "%l", "%M", "%p", "%P", "%X", "%r", "%R", "%T" };
+
+ int _changedCallbackDepth = 0;
+
+ protected override void OnElementChanged(ElementChangedEventArgs<DateTimeView> e)
+ {
+ if (Control == null)
+ {
+ var selector = new EDateTimeSelector(TForms.Context.MainWindow);
+ SetNativeControl(selector);
+ }
+
+ if (e.OldElement != null)
+ {
+ Control.DateTimeChanged -= DateTimeChangedHandler;
+ }
+
+ if (e.NewElement != null)
+ {
+ Control.DateTimeChanged += DateTimeChangedHandler;
+ }
+
+ UpdateMaximumDate();
+ UpdateMinimumDate();
+ UpdateDate();
+ UpdateDisplayFormat();
+
+ base.OnElementChanged(e);
+ }
+
+ protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
+ {
+ if (e.PropertyName == DateTimeView.DateTimeProperty.PropertyName)
+ {
+ UpdateDate();
+ }
+ else if (e.PropertyName == DateTimeView.MinimumDateProperty.PropertyName)
+ {
+ UpdateMinimumDate();
+ }
+ else if (e.PropertyName == DateTimeView.MaximumDateProperty.PropertyName)
+ {
+ UpdateMaximumDate();
+ }
+ else if (e.PropertyName == DateTimeView.DisplayFormatProperty.PropertyName)
+ {
+ UpdateDisplayFormat();
+ }
+
+ base.OnElementPropertyChanged(sender, e);
+ }
+
+ void DateTimeChangedHandler(object sender, ElmSharp.DateChangedEventArgs e)
+ {
+ _changedCallbackDepth++;
+ Element.DateTime = e.NewDate;
+ _changedCallbackDepth--;
+ }
+
+ void UpdateDisplayFormat()
+ {
+ string targetStyle = DateStyle;
+ string targetFormat = Element.DisplayFormat;
+
+ bool isTimeFormat = UseDateFormat.Count(b => targetFormat.Contains(b)) == 0;
+ bool isDateFormat = UseTimeFormat.Count(b => targetFormat.Contains(b)) == 0;
+
+ if (isTimeFormat && isDateFormat == false)
+ targetStyle = TimeStyle;
+ else if (isDateFormat && isTimeFormat == false)
+ targetStyle = DateStyle;
+
+ Control.Style = targetStyle;
+ Control.Format = targetFormat;
+ }
+
+ void UpdateMinimumDate()
+ {
+ Control.MinimumDateTime = Element.MinimumDate;
+ }
+
+ void UpdateMaximumDate()
+ {
+ Control.MaximumDateTime = Element.MaximumDate;
+ }
+
+ void UpdateDate()
+ {
+ if (_changedCallbackDepth == 0)
+ {
+ Control.DateTime = Element.DateTime;
+ }
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using Xamarin.Forms;
+
+namespace Tizen.Xamarin.Forms.Extension
+{
+ /// <summary>
+ /// The Datetime view is used to display the input date & time values.
+ /// </summary>
+ /// <example>
+ /// <code>
+ /// var dateView = new DateTimeView
+ /// {
+ /// HorizontalOptions = LayoutOptions.Center,
+ /// VerticalOptions = LayoutOptions.Start,
+ /// DateTime = DateTime.Now,
+ /// MaximumDate = new DateTime(2030, 12, 31),
+ /// MinimumDate = new DateTime(2017, 1, 1),
+ /// DisplayFormat = "%F",
+ /// }
+ /// </code>
+ /// </example>
+ public class DateTimeView : View
+ {
+ /// <summary>
+ /// Identifies the DateTime bindable property.
+ /// </summary>
+ public static readonly BindableProperty DateTimeProperty = BindableProperty.Create(nameof(DateTime), typeof(DateTime), typeof(DateTimeView), DateTime.Now, BindingMode.TwoWay, coerceValue: CoerceDate,
+ propertyChanged: DatePropertyChanged);
+
+ /// <summary>
+ /// Identifies the DisplayFormat bindable property.
+ /// </summary>
+ public static readonly BindableProperty DisplayFormatProperty = BindableProperty.Create(nameof(DisplayFormat), typeof(string), typeof(DateTimeView), "%F");
+
+ /// <summary>
+ /// Identifies the MinimumDate bindable property.
+ /// </summary>
+ public static readonly BindableProperty MinimumDateProperty = BindableProperty.Create(nameof(MinimumDate), typeof(DateTime), typeof(DateTimeView), new DateTime(1900, 1, 1),
+ validateValue: ValidateMinimumDate, coerceValue: CoerceMinimumDate);
+
+ /// <summary>
+ /// Identifies the MaximumDate bindable property.
+ /// </summary>
+ public static readonly BindableProperty MaximumDateProperty = BindableProperty.Create(nameof(MaximumDate), typeof(DateTime), typeof(DateTimeView), new DateTime(2100, 12, 31),
+ validateValue: ValidateMaximumDate, coerceValue: CoerceMaximumDate);
+
+ /// <summary>
+ /// Gets or sets the current value of a DateTime.
+ /// </summary>
+ public DateTime DateTime
+ {
+ get { return (DateTime)GetValue(DateTimeProperty); }
+ set { SetValue(DateTimeProperty, value); }
+ }
+
+ /// <summary>
+ /// Gets or sets the datetime format.
+ /// Format is a combination of allowed LIBC date format specifiers like: "%b %d, %Y %I : %M %p".
+ /// </summary>
+ /// <remarks>
+ /// These specifiers can be arranged in any order and the widget displays the fields accordingly.
+ /// However, you can not use Date and Time settings in combination.
+ /// The default format is taken as per the system locale settings.
+ /// </remarks>
+ /// <remarks>
+ /// The maximum allowed format length is 64 chars.
+ /// The format can include separators for each individual datetime field except for the AM/PM field.
+ /// Each separator can be a maximum of 6 UTF-8 bytes.Space is also taken as a separator.
+ /// Following are the allowed set of format specifiers for each datetime field.
+ /// %Y : The year as a decimal number including the century.
+ /// %m : The month as a decimal number (range 01 to 12).
+ /// %b : The abbreviated month name according to the current locale.
+ /// %B : The full month name according to the current locale.
+ /// %h : The abbreviated month name according to the current locale(same as %b).
+ /// %d : The day of the month as a decimal number(range 01 to 31).
+ /// %e : The day of the month as a decimal number(range 1 to 31). Single digits are preceded by a blank.
+ /// %I : The hour as a decimal number using a 12-hour clock(range 01 to 12).
+ /// %H : The hour as a decimal number using a 24-hour clock(range 00 to 23).
+ /// %k : The hour(24-hour clock) as a decimal number(range 0 to 23). Single digits are preceded by a blank.
+ /// %l : The hour(12-hour clock) as a decimal number(range 1 to 12). Single digits are preceded by a blank.
+ /// %M : The minute as a decimal number(range 00 to 59).
+ /// %p : Either 'AM' or 'PM' according to the given time value, or the corresponding strings for the current locale.Noon is treated as 'PM' and midnight as 'AM'.
+ /// %P : Like p, but in lower case: 'am' or 'pm' or a corresponding string for the current locale.
+ /// %c : The preferred date and time representation for the current locale.
+ /// %x : The preferred date representation for the current locale without the time.
+ /// %X : The preferred time representation for the current locale without the date.
+ /// %r : The complete calendar time using the AM/PM format of the current locale.
+ /// %R : The hour and minute in decimal numbers using the format H:M.
+ /// %T : The time of the day in decimal numbers using the format H:M:S.
+ /// %F : The date using the format %Y-%m-%d.
+ /// </remarks>
+ public string DisplayFormat
+ {
+ get { return (string)GetValue(DisplayFormatProperty); }
+ set { SetValue(DisplayFormatProperty, value); }
+ }
+
+ /// <summary>
+ /// Gets or sets the upper boundary of a DateTime value.
+ /// </summary>
+ public DateTime MaximumDate
+ {
+ get { return (DateTime)GetValue(MaximumDateProperty); }
+ set { SetValue(MaximumDateProperty, value); }
+ }
+
+ /// <summary>
+ /// Gets or sets the lower boundary of a DateTime value.
+ /// </summary>
+ public DateTime MinimumDate
+ {
+ get { return (DateTime)GetValue(MinimumDateProperty); }
+ set { SetValue(MinimumDateProperty, value); }
+ }
+
+ /// <summary>
+ /// An event fired when the DateTime property changes.
+ /// </summary>
+ public event EventHandler<DateChangedEventArgs> DateChanged;
+
+ static object CoerceDate(BindableObject bindable, object value)
+ {
+ var picker = (DateTimeView)bindable;
+ DateTime dateValue = (DateTime)value;
+
+ if (dateValue > picker.MaximumDate)
+ dateValue = picker.MaximumDate;
+
+ if (dateValue < picker.MinimumDate)
+ dateValue = picker.MinimumDate;
+
+ return dateValue;
+ }
+
+ static object CoerceMaximumDate(BindableObject bindable, object value)
+ {
+ DateTime dateValue = ((DateTime)value).Date;
+ var selector = (DateTimeView)bindable;
+ if (selector.DateTime > dateValue)
+ selector.DateTime = dateValue;
+
+ return dateValue;
+ }
+
+ static object CoerceMinimumDate(BindableObject bindable, object value)
+ {
+ DateTime dateValue = ((DateTime)value).Date;
+ var selector = (DateTimeView)bindable;
+ if (selector.DateTime < dateValue)
+ selector.DateTime = dateValue;
+
+ return dateValue;
+ }
+
+ static void DatePropertyChanged(BindableObject bindable, object oldValue, object newValue)
+ {
+ var selector = (DateTimeView)bindable;
+ EventHandler<DateChangedEventArgs> selected = selector.DateChanged;
+
+ if (selected != null)
+ selected(selector, new DateChangedEventArgs((DateTime)oldValue, (DateTime)newValue));
+ }
+
+ static bool ValidateMaximumDate(BindableObject bindable, object value)
+ {
+ return (DateTime)value >= ((DateTimeView)bindable).MinimumDate;
+ }
+
+ static bool ValidateMinimumDate(BindableObject bindable, object value)
+ {
+ return (DateTime)value <= ((DateTimeView)bindable).MaximumDate;
+ }
+ }
+}
\ No newline at end of file