From 724fb3611729ffc8aecce84ddb7cdbf6f98ff9bd Mon Sep 17 00:00:00 2001 From: Daniel Dinca Date: Thu, 25 Jul 2024 18:35:59 +0300 Subject: [PATCH] feat: add dateonly converter --- .../Windows/Markup/TypeConverterHelper.cs | 24 +++++ .../Xaml/Replacements/DateOnlyConverter2.cs | 98 +++++++++++++++++ .../Xaml/Replacements/TimeOnlyConverter2.cs | 100 ++++++++++++++++++ .../Xaml/Schema/BuiltInValueConverter.cs | 18 ++++ 4 files changed, 240 insertions(+) create mode 100644 src/System.Xaml/System/Xaml/Replacements/DateOnlyConverter2.cs create mode 100644 src/System.Xaml/System/Xaml/Replacements/TimeOnlyConverter2.cs diff --git a/src/System.Xaml/System/Windows/Markup/TypeConverterHelper.cs b/src/System.Xaml/System/Windows/Markup/TypeConverterHelper.cs index 79400591..62f01be1 100644 --- a/src/System.Xaml/System/Windows/Markup/TypeConverterHelper.cs +++ b/src/System.Xaml/System/Windows/Markup/TypeConverterHelper.cs @@ -244,6 +244,14 @@ internal static Type GetCoreConverterTypeFromCustomType(Type type) { converterType = typeof(DateTimeConverter2); } + else if (typeof(DateOnly).IsAssignableFrom(type)) + { + typeConverter = typeof(DateOnlyConverter2); + } + else if (typeof(TimeOnly).IsAssignableFrom(type)) + { + typeConverter = typeof(TimeOnlyConverter2); + } return converterType; } @@ -339,6 +347,14 @@ private static TypeConverter GetCoreConverterFromCoreType(Type type) { typeConverter = new System.ComponentModel.NullableConverter(type); } + else if (type == typeof(DateOnly)) + { + typeConverter = new DateOnlyConverter2(); + } + else if (type == typeof(TimeOnly)) + { + typeConverter = new TimeOnlyConverter2(); + } return typeConverter; } @@ -439,6 +455,14 @@ internal static TypeConverter GetCoreConverterFromCustomType(Type type) { typeConverter = new System.Xaml.Replacements.UriTypeConverter(); } + else if (typeof(DateOnly).IsAssignableFrom(type)) + { + typeConverter = new DateOnlyConverter2(); + } + else if (typeof(TimeOnly).IsAssignableFrom(type)) + { + typeConverter = new TimeOnlyConverter2(); + } return typeConverter; } diff --git a/src/System.Xaml/System/Xaml/Replacements/DateOnlyConverter2.cs b/src/System.Xaml/System/Xaml/Replacements/DateOnlyConverter2.cs new file mode 100644 index 00000000..b45146a9 --- /dev/null +++ b/src/System.Xaml/System/Xaml/Replacements/DateOnlyConverter2.cs @@ -0,0 +1,98 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.ComponentModel; +using System.ComponentModel.Design.Serialization; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; + +namespace System.Xaml.Replacements +{ + /// + /// Provides a type converter to convert objects to and from various other representations. + /// + internal class DateOnlyConverter2 : TypeConverter + { + /// + /// Gets a value indicating whether this converter can convert an object in the given source type to a + /// object using the specified context. + /// + /// + public override bool CanConvertFrom(ITypeDescriptorContext? context, Type sourceType) + { + return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType); + } + + /// + public override bool CanConvertTo(ITypeDescriptorContext? context, [NotNullWhen(true)] Type? destinationType) + { + return destinationType == typeof(InstanceDescriptor) || base.CanConvertTo(context, destinationType); + } + + /// + /// Converts the given value object to a object. + /// + /// + public override object? ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value) + { + if (value is string text) + { + text = text.Trim(); + if (text.Length == 0) + { + return DateOnly.MinValue; + } + + // See if we have a culture info to parse with. If so, then use it. + DateTimeFormatInfo? formatInfo = null; + + if (culture != null) + { + formatInfo = (DateTimeFormatInfo?)culture.GetFormat(typeof(DateTimeFormatInfo)); + } + + if (formatInfo != null) + { + return DateOnly.Parse(text, formatInfo); + } + else + { + return DateOnly.Parse(text, culture); + } + } + + return base.ConvertFrom(context, culture, value); + } + + /// + /// Converts the given value object from a object using the arguments. + /// + /// + public override object? ConvertTo(ITypeDescriptorContext? context, CultureInfo? culture, object? value, Type destinationType) + { + if (destinationType == typeof(string) && value is DateOnly dateOnly) + { + if (dateOnly == DateOnly.MinValue) + { + return string.Empty; + } + + culture ??= CultureInfo.CurrentCulture; + + if (culture == CultureInfo.InvariantCulture) + { + return dateOnly.ToString("yyyy-MM-dd", culture); + } + + return dateOnly.ToString(culture.DateTimeFormat.ShortDatePattern, culture); + } + + if (destinationType == typeof(InstanceDescriptor) && value is DateOnly date) + { + return new InstanceDescriptor(typeof(DateOnly).GetConstructor(new Type[] { typeof(int), typeof(int), typeof(int) }), new object[] { date.Year, date.Month, date.Day }); + } + + return base.ConvertTo(context, culture, value, destinationType); + } + } +} \ No newline at end of file diff --git a/src/System.Xaml/System/Xaml/Replacements/TimeOnlyConverter2.cs b/src/System.Xaml/System/Xaml/Replacements/TimeOnlyConverter2.cs new file mode 100644 index 00000000..ce68fcaf --- /dev/null +++ b/src/System.Xaml/System/Xaml/Replacements/TimeOnlyConverter2.cs @@ -0,0 +1,100 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.ComponentModel; +using System.ComponentModel.Design.Serialization; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; + +namespace System.Xaml.Replacements +{ + /// + /// Provides a type converter to convert objects to and from various other representations. + /// + internal class TimeOnlyConverter2 : TypeConverter + { + /// + /// Gets a value indicating whether this converter can convert an object in the given source type to a + /// object using the specified context. + /// + /// + public override bool CanConvertFrom(ITypeDescriptorContext? context, Type sourceType) + { + return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType); + } + + /// + public override bool CanConvertTo(ITypeDescriptorContext? context, [NotNullWhen(true)] Type? destinationType) + { + return destinationType == typeof(InstanceDescriptor) || base.CanConvertTo(context, destinationType); + } + + /// + /// Converts the given value object to a object. + /// + /// + public override object? ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value) + { + if (value is string text) + { + text = text.Trim(); + if (text.Length == 0) + { + return TimeOnly.MinValue; + } + + + // See if we have a culture info to parse with. If so, then use it. + DateTimeFormatInfo? formatInfo = null; + + if (culture != null) + { + formatInfo = (DateTimeFormatInfo?)culture.GetFormat(typeof(DateTimeFormatInfo)); + } + + if (formatInfo != null) + { + return TimeOnly.Parse(text, formatInfo); + } + else + { + return TimeOnly.Parse(text, culture); + } + } + + return base.ConvertFrom(context, culture, value); + } + + /// + /// Converts the given value object from a object using the arguments. + /// + /// + public override object? ConvertTo(ITypeDescriptorContext? context, CultureInfo? culture, object? value, Type destinationType) + { + if (destinationType == typeof(string) && value is TimeOnly timeOnly) + { + if (timeOnly == TimeOnly.MinValue) + { + return string.Empty; + } + + culture ??= CultureInfo.CurrentCulture; + + return timeOnly.ToString(culture.DateTimeFormat.ShortTimePattern, culture); + } + + if (destinationType == typeof(InstanceDescriptor) && value is TimeOnly time) + { + if (time.Ticks == 0) + { + return new InstanceDescriptor(typeof(TimeOnly).GetConstructor(new Type[] { typeof(long) }), new object[] { time.Ticks }); + } + + return new InstanceDescriptor(typeof(TimeOnly).GetConstructor(new Type[] { typeof(int), typeof(int), typeof(int), typeof(int), typeof(int) }), + new object[] { time.Hour, time.Minute, time.Second, time.Millisecond}); + } + + return base.ConvertTo(context, culture, value, destinationType); + } + } +} \ No newline at end of file diff --git a/src/System.Xaml/System/Xaml/Schema/BuiltInValueConverter.cs b/src/System.Xaml/System/Xaml/Schema/BuiltInValueConverter.cs index 828933ca..7eb2d4d1 100644 --- a/src/System.Xaml/System/Xaml/Schema/BuiltInValueConverter.cs +++ b/src/System.Xaml/System/Xaml/Schema/BuiltInValueConverter.cs @@ -56,6 +56,8 @@ internal static class BuiltInValueConverter private static XamlValueConverter s_TypeList; private static XamlValueConverter s_DateTime; private static XamlValueConverter s_DateTimeOffset; + private static XamlValueConverter s_DateOnly; + private static XamlValueConverter s_TimeOnly; private static XamlValueConverter s_CultureInfo; private static XamlValueConverter s_StringSerializer; private static XamlValueConverter s_Delegate; @@ -267,6 +269,22 @@ internal static XamlValueConverter GetTypeConverter(Type targetTy } return s_DateTimeOffset; } + if (typeof(DateOnly) == targetType) + { + if (s_DateOnly is null) + { + s_DateOnly = new BuiltInValueConverter(typeof(DateOnlyConverter2), () => new DateOnlyConverter2()); + } + return s_DateOnly; + } + if (typeof(TimeOnly) == targetType) + { + if (s_TimeOnly is null) + { + s_TimeOnly = new BuiltInValueConverter(typeof(TimeOnlyConverter2), () => new TimeOnlyConverter2()); + } + return s_TimeOnly; + } if (typeof(CultureInfo).IsAssignableFrom(targetType)) { if (s_CultureInfo is null)