Since Windows 8.1 is available the DatePicker and TimePicker controls. These controls allow an application to easily choose a date or time.
Yet, as the DatePicker.Date property is of type DateTimeOffset and TimePicker.Time property is of type TimeSpan, they can not be binded directly to a variable or property of type DateTime.
However, this limitation can be easily overcome by implementing a simple converter class (derived from the IValueConverter interface) and may even support two way data binding.
That is what we show in the code below.
Helper class to convert DateTime to DateTimeOffset and Timespan and vice-versa.
/// <summary> /// Implements a (helper) class to convert date and time values. /// </summary> public static class DateTimeConverter { /// <summary> /// Converts from DateTime to TimaSpan. /// </summary> /// <param name="dt">The source DateTime value.</param> /// <returns>Returns the time portion of DateTime in the form of TimeSpan if succeeded, null otherwise.</returns> public static TimeSpan? DateTimeToTimeSpan(DateTime dt) { TimeSpan FResult; try { FResult = dt - dt.Date; } catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex.Message); return null; } return FResult; } /// <summary> /// Converts from Timespan to DateTime. /// </summary> /// <param name="ts">The source TimeSpan value.</param> /// <returns>Returns a DateTime filled with date equals to mindate and time equals to time in timespan if succeeded, null otherwise.</returns> public static DateTime? TimeSpanToDateTime(TimeSpan ts) { DateTime? FResult = null; try { string year = string.Format("{0:0000}", DateTime.MinValue.Date.Year); string month = string.Format("{0:00}", DateTime.MinValue.Date.Month); string day = string.Format("{0:00}", DateTime.MinValue.Date.Day); string hours = string.Format("{0:00}", ts.Hours); string minutes = string.Format("{0:00}", ts.Minutes); string seconds = string.Format("{0:00}", ts.Seconds); string dSep = "-"; string tSep = ":"; string dtSep = "T"; // yyyy-mm-ddTHH:mm:ss string dtStr = string.Concat(year, dSep, month, dSep, day, dtSep, hours, tSep, minutes, tSep, seconds); DateTime dt; if (DateTime.TryParseExact(dtStr, "yyyy-MM-ddTHH:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal, out dt)) { FResult = dt; } } catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex.Message); throw; } return FResult; } /// <summary> /// Converts from DateTime to DateTimeOffSet. /// </summary> /// <param name="dt">The source DateTime to convert.</param> /// <returns>Returns a DateTimeOffSet if succeeded, null otherwise.</returns> public static DateTimeOffset? DateTimeToDateTimeOffSet(DateTime dt) { try { return new DateTimeOffset(dt); } catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex.Message); return null; } } /// <summary> /// Converts from DateTimeOffSet to DateTime. /// </summary> /// <param name="dto">The source DateTimeOffSet to convert.</param> /// <returns>Returns a DateTime if succeeded, null otherwise.</returns> public static DateTime? DateTimeOffSetToDateTime(DateTimeOffset dto) { try { return dto.DateTime; } catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex.Message); return null; } } }
DateTime to DateTimeOffset converter class.
/// <summary> /// Implements a databind converter from DateTime to DateTimeOffset. /// </summary> public class DateTimeToDateTimeOffsetConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, string language) { try { DateTime date = (DateTime)value; DateTimeOffset? dto = DateTimeConverter.DateTimeToDateTimeOffSet(date); return dto.GetValueOrDefault(DateTimeOffset.MinValue); } catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex.Message); return DateTimeOffset.MinValue; } } public object ConvertBack(object value, Type targetType, object parameter, string language) { try { DateTimeOffset dto = (DateTimeOffset)value; return dto.DateTime; } catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex.Message); return DateTime.MinValue; } } }
DateTime to TimeSpan converter class.
/// <summary> /// Implements a databind converter to convert from DateTime to TimeSpan and vice-versa. /// </summary> public class DateTimeToTimeSpanConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, string language) { try { DateTime dt = (DateTime)value; TimeSpan? ts = DateTimeConverter.DateTimeToTimeSpan(dt); return ts.GetValueOrDefault(TimeSpan.MinValue); } catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex.Message); return TimeSpan.MinValue; } } public object ConvertBack(object value, Type targetType, object parameter, string language) { try { TimeSpan ts = (TimeSpan)value; DateTime? dt = DateTimeConverter.TimeSpanToDateTime(ts); return dt.GetValueOrDefault(DateTime.MinValue); } catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex.Message); return DateTime.MinValue; } } }
With that created, I can add a resource to the page, and then modify the markup for the DatePicker and TimePicker to bind its Date and Time properties to (supposed) “SomeDateTimeDate” and “SomeDateTimeTime” properties (type DateTime) in your view model.
<Page.Resources> <Converters:DateTimeToDateTimeOffsetConverter x:Key="DateTimeToDateTimeOffsetConverter"/> <Converters:DateTimeToTimeSpanConverter x:Key="DateTimeToTimeSpanConverter"/> </Page.Resources> <!-- ... --> <DatePicker Header="My date" Margin="10" FontSize="24" Date="{Binding SomeDateTimeDate, Converter={StaticResource DateTimeToDateTimeOffsetConverter}, Mode=TwoWay}"/> <TimePicker Header="My time" Margin="10" FontSize="24" Time="{Binding SomeDateTimeTime, Converter={StaticResource DateTimeToTimeSpanConverter}, Mode=TwoWay}" />
That’s all.