You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Connected.Components/Utilities/BindingConverters/DefaultConverter.cs

465 lines
11 KiB

using System.Globalization;
2 years ago
namespace Connected;
/// <summary>
/// A universal T to string binding converter
/// </summary>
public class DefaultConverter<T> : ToStringConverter<T>
2 years ago
{
protected override string? ConvertValue(T? value) => ConvertToString(value);
protected override T? ConvertValueBack(string? value) => ConvertFromString(value);
public string DefaultTimeSpanFormat { get; set; } = "c";
protected virtual T? ConvertFromString(string? value)
{
try
{
/*
* This is important, or otherwise all the TryParse down there might fail.
*/
if (string.IsNullOrEmpty(value))
{
return default;
}
/*
* String
*/
else if (typeof(T) == typeof(string))
{
return (T)(object)value;
}
/*
* Char
*/
else if (typeof(T) == typeof(char) || typeof(T) == typeof(char?))
{
return (T)(object)value[0];
}
/*
* Bool
*/
else if (typeof(T) == typeof(bool) || typeof(T) == typeof(bool?))
{
var lowerValue = value.ToLowerInvariant();
if (lowerValue is "true" or "on")
return (T)(object)true;
if (lowerValue is "false" or "off")
return (T)(object)false;
TriggerError("Not a valid boolean");
}
/*
* Sbyte
*/
else if (typeof(T) == typeof(sbyte) || typeof(T) == typeof(sbyte?))
{
if (sbyte.TryParse(value, NumberStyles.Integer | NumberStyles.AllowThousands, Culture, out var parsedValue))
return (T)(object)parsedValue;
TriggerError("Not a valid number");
}
/*
* Byte
*/
else if (typeof(T) == typeof(byte) || typeof(T) == typeof(byte?))
{
if (byte.TryParse(value, NumberStyles.Integer | NumberStyles.AllowThousands, Culture, out var parsedValue))
return (T)(object)parsedValue;
TriggerError("Not a valid number");
}
/*
* Short
*/
else if (typeof(T) == typeof(short) || typeof(T) == typeof(short?))
{
if (short.TryParse(value, NumberStyles.Integer | NumberStyles.AllowThousands, Culture, out var parsedValue))
return (T)(object)parsedValue;
TriggerError("Not a valid number");
}
/*
* Ushort
*/
else if (typeof(T) == typeof(ushort) || typeof(T) == typeof(ushort?))
{
if (ushort.TryParse(value, NumberStyles.Integer | NumberStyles.AllowThousands, Culture, out var parsedValue))
return (T)(object)parsedValue;
TriggerError("Not a valid number");
}
/*
* Int
*/
else if (typeof(T) == typeof(int) || typeof(T) == typeof(int?))
{
if (int.TryParse(value, NumberStyles.Integer | NumberStyles.AllowThousands, Culture, out var parsedValue))
return (T)(object)parsedValue;
TriggerError("Not a valid number");
}
/*
* Uint
*/
else if (typeof(T) == typeof(uint) || typeof(T) == typeof(uint?))
{
if (uint.TryParse(value, NumberStyles.Integer | NumberStyles.AllowThousands, Culture, out var parsedValue))
return (T)(object)parsedValue;
TriggerError("Not a valid number");
}
/*
* Long
*/
else if (typeof(T) == typeof(long) || typeof(T) == typeof(long?))
{
if (long.TryParse(value, NumberStyles.Integer | NumberStyles.AllowThousands, Culture, out var parsedValue))
return (T)(object)parsedValue;
TriggerError("Not a valid number");
}
/*
* Ulong
*/
else if (typeof(T) == typeof(ulong) || typeof(T) == typeof(ulong?))
{
if (ulong.TryParse(value, NumberStyles.Integer | NumberStyles.AllowThousands, Culture, out var parsedValue))
return (T)(object)parsedValue;
TriggerError("Not a valid number");
}
/*
* Float
*/
else if (typeof(T) == typeof(float) || typeof(T) == typeof(float?))
{
if (float.TryParse(value, NumberStyles.Any, Culture, out var parsedValue))
return (T)(object)parsedValue;
TriggerError("Not a valid number");
}
/*
* Double
*/
else if (typeof(T) == typeof(double) || typeof(T) == typeof(double?))
{
if (double.TryParse(value, NumberStyles.Any, Culture, out var parsedValue))
return (T)(object)parsedValue;
TriggerError("Not a valid number");
}
/*
* Decimal
*/
else if (typeof(T) == typeof(decimal) || typeof(T) == typeof(decimal?))
{
if (decimal.TryParse(value, NumberStyles.Any, Culture, out var parsedValue))
return (T)(object)parsedValue;
TriggerError("Not a valid number");
}
/*
* Guid
*/
else if (typeof(T) == typeof(Guid) || typeof(T) == typeof(Guid?))
{
if (Guid.TryParse(value, out var parsedValue))
return (T)(object)parsedValue;
2 years ago
TriggerError("Not a valid GUID");
}
/*
* Enum
*/
else if (IsNullableEnum(typeof(T)))
{
var enum_type = Nullable.GetUnderlyingType(typeof(T));
2 years ago
if (Enum.TryParse(enum_type, value, out var parsedValue))
return (T)parsedValue;
2 years ago
TriggerError("Not a value of " + enum_type.Name);
}
else if (typeof(T).IsEnum)
{
if (Enum.TryParse(typeof(T), value, out var parsedValue))
return (T)parsedValue;
TriggerError("Not a value of " + typeof(T).Name);
}
/*
* DateTime
*/
else if (typeof(T) == typeof(DateTime) || typeof(T) == typeof(DateTime?))
{
try
{
return (T)(object)DateTime.ParseExact(value, Format ?? Culture.DateTimeFormat.ShortDatePattern, Culture);
}
catch (FormatException)
{
TriggerError("Not a valid date time");
}
}
/*
* Timespan
*/
else if (typeof(T) == typeof(TimeSpan) || typeof(T) == typeof(TimeSpan?))
{
try
{
return (T)(object)TimeSpan.ParseExact(value, Format ?? DefaultTimeSpanFormat, Culture);
}
catch (FormatException)
{
TriggerError("Not a valid time span");
}
}
else
{
TriggerError($"Conversion to type {typeof(T)} not implemented");
}
}
catch (Exception e)
{
TriggerError("Conversion error: " + e.Message);
}
return default;
}
2 years ago
protected virtual string? ConvertToString(T? arg)
{
/*
* This catches all null values. No additional null checks necessary.
*/
if (arg is null)
return null;
2 years ago
try
{
/*
* String
*/
if (typeof(T) == typeof(string))
{
return (string)(object)arg;
}
/*
* Char
*/
else if (typeof(T) == typeof(char))
{
return ((char)(object)arg).ToString(Culture);
}
else if (typeof(T) == typeof(char?))
{
return ((char?)(object)arg).Value.ToString(Culture);
}
/*
* Bool
*/
else if (typeof(T) == typeof(bool))
{
return ((bool)(object)arg).ToString(CultureInfo.InvariantCulture);
}
else if (typeof(T) == typeof(bool?))
{
return ((bool?)(object)arg).Value.ToString(CultureInfo.InvariantCulture);
}
/*
* Sbyte
*/
else if (typeof(T) == typeof(sbyte))
{
return ((sbyte)(object)arg).ToString(Format, Culture);
}
else if (typeof(T) == typeof(sbyte?))
{
return ((sbyte?)(object)arg).Value.ToString(Format, Culture);
}
/*
* Byte
*/
else if (typeof(T) == typeof(byte))
{
return ((byte)(object)arg).ToString(Format, Culture);
}
else if (typeof(T) == typeof(byte?))
{
return ((byte?)(object)arg).Value.ToString(Format, Culture);
}
/*
* Short
*/
else if (typeof(T) == typeof(short))
{
return ((short)(object)arg).ToString(Format, Culture);
}
else if (typeof(T) == typeof(short?))
{
return ((short?)(object)arg).Value.ToString(Format, Culture);
}
/*
* Ushort
*/
else if (typeof(T) == typeof(ushort))
{
return ((ushort)(object)arg).ToString(Format, Culture);
}
else if (typeof(T) == typeof(ushort?))
{
return ((ushort?)(object)arg).Value.ToString(Format, Culture);
}
/*
* Int
*/
else if (typeof(T) == typeof(int))
{
return ((int)(object)arg).ToString(Format, Culture);
}
else if (typeof(T) == typeof(int?))
{
return ((int?)(object)arg).Value.ToString(Format, Culture);
}
/*
* Uint
*/
else if (typeof(T) == typeof(uint))
{
return ((uint)(object)arg).ToString(Format, Culture);
}
else if (typeof(T) == typeof(uint?))
{
return ((uint?)(object)arg).Value.ToString(Format, Culture);
}
/*
* Long
*/
else if (typeof(T) == typeof(long))
{
return ((long)(object)arg).ToString(Format, Culture);
}
else if (typeof(T) == typeof(long?))
{
return ((long?)(object)arg).Value.ToString(Format, Culture);
}
/*
* Ulong
*/
else if (typeof(T) == typeof(ulong))
{
return ((ulong)(object)arg).ToString(Format, Culture);
}
else if (typeof(T) == typeof(ulong?))
{
return ((ulong?)(object)arg).Value.ToString(Format, Culture);
}
/*
* Float
*/
else if (typeof(T) == typeof(float))
{
return ((float)(object)arg).ToString(Format, Culture);
}
else if (typeof(T) == typeof(float?))
{
return ((float?)(object)arg).Value.ToString(Format, Culture);
}
/*
* Double
*/
else if (typeof(T) == typeof(double))
{
return ((double)(object)arg).ToString(Format, Culture);
}
else if (typeof(T) == typeof(double?))
{
return ((double?)(object)arg).Value.ToString(Format, Culture);
}
/*
* Decimal
*/
else if (typeof(T) == typeof(decimal))
{
return ((decimal)(object)arg).ToString(Format, Culture);
}
else if (typeof(T) == typeof(decimal?))
{
return ((decimal?)(object)arg).Value.ToString(Format, Culture);
}
/*
* Guid
*/
else if (typeof(T) == typeof(Guid))
{
var value = (Guid)(object)arg;
return value.ToString();
}
else if (typeof(T) == typeof(Guid?))
{
var value = (Guid?)(object)arg;
return value.Value.ToString();
}
/*
* Enum
*/
else if (IsNullableEnum(typeof(T)))
{
var value = (Enum)(object)arg;
return value.ToString();
}
else if (typeof(T).IsEnum)
{
var value = (Enum)(object)arg;
return value.ToString();
}
/*
* DateTime
*/
else if (typeof(T) == typeof(DateTime))
{
var value = (DateTime)(object)arg;
return value.ToString(Format ?? Culture.DateTimeFormat.ShortDatePattern, Culture);
}
else if (typeof(T) == typeof(DateTime?))
{
var value = (DateTime?)(object)arg;
return value.Value.ToString(Format ?? Culture.DateTimeFormat.ShortDatePattern, Culture);
}
/*
* Timespan
*/
else if (typeof(T) == typeof(TimeSpan))
{
var value = (TimeSpan)(object)arg;
return value.ToString(Format ?? DefaultTimeSpanFormat, Culture);
}
else if (typeof(T) == typeof(TimeSpan?))
{
var value = (TimeSpan?)(object)arg;
return value.Value.ToString(Format ?? DefaultTimeSpanFormat, Culture);
}
2 years ago
return arg.ToString();
}
catch (FormatException e)
{
TriggerError("Conversion error: " + e.Message);
return null;
}
}
2 years ago
public static bool IsNullableEnum(Type t)
{
var u = Nullable.GetUnderlyingType(t);
2 years ago
return (u is not null) && u.IsEnum;
}
2 years ago
}