|
|
@ -7,13 +7,21 @@ namespace Connected
|
|
|
|
/// <summary>
|
|
|
|
/// <summary>
|
|
|
|
/// A universal T to string binding converter
|
|
|
|
/// A universal T to string binding converter
|
|
|
|
/// </summary>
|
|
|
|
/// </summary>
|
|
|
|
public class DefaultConverter<T> : Converter<T>
|
|
|
|
public class DefaultConverter<T> : ToStringConverter<T>
|
|
|
|
{
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
public DefaultConverter()
|
|
|
|
public DefaultConverter()
|
|
|
|
{
|
|
|
|
{
|
|
|
|
SetFunc = ConvertToString;
|
|
|
|
}
|
|
|
|
GetFunc = ConvertFromString;
|
|
|
|
|
|
|
|
|
|
|
|
protected override string? ConvertValue(T? value)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
return ConvertToString(value);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
protected override T? ConvertValueBack(string? value)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
return ConvertFromString(value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public string DefaultTimeSpanFormat { get; set; } = "c";
|
|
|
|
public string DefaultTimeSpanFormat { get; set; } = "c";
|
|
|
@ -42,91 +50,91 @@ namespace Connected
|
|
|
|
return (T)(object)true;
|
|
|
|
return (T)(object)true;
|
|
|
|
if (lowerValue is "false" or "off")
|
|
|
|
if (lowerValue is "false" or "off")
|
|
|
|
return (T)(object)false;
|
|
|
|
return (T)(object)false;
|
|
|
|
UpdateGetError("Not a valid boolean");
|
|
|
|
TriggerError("Not a valid boolean");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// sbyte
|
|
|
|
// sbyte
|
|
|
|
else if (typeof(T) == typeof(sbyte) || typeof(T) == typeof(sbyte?))
|
|
|
|
else if (typeof(T) == typeof(sbyte) || typeof(T) == typeof(sbyte?))
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if (sbyte.TryParse(value, NumberStyles.Integer | NumberStyles.AllowThousands, Culture, out var parsedValue))
|
|
|
|
if (sbyte.TryParse(value, NumberStyles.Integer | NumberStyles.AllowThousands, Culture, out var parsedValue))
|
|
|
|
return (T)(object)parsedValue;
|
|
|
|
return (T)(object)parsedValue;
|
|
|
|
UpdateGetError("Not a valid number");
|
|
|
|
TriggerError("Not a valid number");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// byte
|
|
|
|
// byte
|
|
|
|
else if (typeof(T) == typeof(byte) || typeof(T) == typeof(byte?))
|
|
|
|
else if (typeof(T) == typeof(byte) || typeof(T) == typeof(byte?))
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if (byte.TryParse(value, NumberStyles.Integer | NumberStyles.AllowThousands, Culture, out var parsedValue))
|
|
|
|
if (byte.TryParse(value, NumberStyles.Integer | NumberStyles.AllowThousands, Culture, out var parsedValue))
|
|
|
|
return (T)(object)parsedValue;
|
|
|
|
return (T)(object)parsedValue;
|
|
|
|
UpdateGetError("Not a valid number");
|
|
|
|
TriggerError("Not a valid number");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// short
|
|
|
|
// short
|
|
|
|
else if (typeof(T) == typeof(short) || typeof(T) == typeof(short?))
|
|
|
|
else if (typeof(T) == typeof(short) || typeof(T) == typeof(short?))
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if (short.TryParse(value, NumberStyles.Integer | NumberStyles.AllowThousands, Culture, out var parsedValue))
|
|
|
|
if (short.TryParse(value, NumberStyles.Integer | NumberStyles.AllowThousands, Culture, out var parsedValue))
|
|
|
|
return (T)(object)parsedValue;
|
|
|
|
return (T)(object)parsedValue;
|
|
|
|
UpdateGetError("Not a valid number");
|
|
|
|
TriggerError("Not a valid number");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// ushort
|
|
|
|
// ushort
|
|
|
|
else if (typeof(T) == typeof(ushort) || typeof(T) == typeof(ushort?))
|
|
|
|
else if (typeof(T) == typeof(ushort) || typeof(T) == typeof(ushort?))
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if (ushort.TryParse(value, NumberStyles.Integer | NumberStyles.AllowThousands, Culture, out var parsedValue))
|
|
|
|
if (ushort.TryParse(value, NumberStyles.Integer | NumberStyles.AllowThousands, Culture, out var parsedValue))
|
|
|
|
return (T)(object)parsedValue;
|
|
|
|
return (T)(object)parsedValue;
|
|
|
|
UpdateGetError("Not a valid number");
|
|
|
|
TriggerError("Not a valid number");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// int
|
|
|
|
// int
|
|
|
|
else if (typeof(T) == typeof(int) || typeof(T) == typeof(int?))
|
|
|
|
else if (typeof(T) == typeof(int) || typeof(T) == typeof(int?))
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if (int.TryParse(value, NumberStyles.Integer | NumberStyles.AllowThousands, Culture, out var parsedValue))
|
|
|
|
if (int.TryParse(value, NumberStyles.Integer | NumberStyles.AllowThousands, Culture, out var parsedValue))
|
|
|
|
return (T)(object)parsedValue;
|
|
|
|
return (T)(object)parsedValue;
|
|
|
|
UpdateGetError("Not a valid number");
|
|
|
|
TriggerError("Not a valid number");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// uint
|
|
|
|
// uint
|
|
|
|
else if (typeof(T) == typeof(uint) || typeof(T) == typeof(uint?))
|
|
|
|
else if (typeof(T) == typeof(uint) || typeof(T) == typeof(uint?))
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if (uint.TryParse(value, NumberStyles.Integer | NumberStyles.AllowThousands, Culture, out var parsedValue))
|
|
|
|
if (uint.TryParse(value, NumberStyles.Integer | NumberStyles.AllowThousands, Culture, out var parsedValue))
|
|
|
|
return (T)(object)parsedValue;
|
|
|
|
return (T)(object)parsedValue;
|
|
|
|
UpdateGetError("Not a valid number");
|
|
|
|
TriggerError("Not a valid number");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// long
|
|
|
|
// long
|
|
|
|
else if (typeof(T) == typeof(long) || typeof(T) == typeof(long?))
|
|
|
|
else if (typeof(T) == typeof(long) || typeof(T) == typeof(long?))
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if (long.TryParse(value, NumberStyles.Integer | NumberStyles.AllowThousands, Culture, out var parsedValue))
|
|
|
|
if (long.TryParse(value, NumberStyles.Integer | NumberStyles.AllowThousands, Culture, out var parsedValue))
|
|
|
|
return (T)(object)parsedValue;
|
|
|
|
return (T)(object)parsedValue;
|
|
|
|
UpdateGetError("Not a valid number");
|
|
|
|
TriggerError("Not a valid number");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// ulong
|
|
|
|
// ulong
|
|
|
|
else if (typeof(T) == typeof(ulong) || typeof(T) == typeof(ulong?))
|
|
|
|
else if (typeof(T) == typeof(ulong) || typeof(T) == typeof(ulong?))
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if (ulong.TryParse(value, NumberStyles.Integer | NumberStyles.AllowThousands, Culture, out var parsedValue))
|
|
|
|
if (ulong.TryParse(value, NumberStyles.Integer | NumberStyles.AllowThousands, Culture, out var parsedValue))
|
|
|
|
return (T)(object)parsedValue;
|
|
|
|
return (T)(object)parsedValue;
|
|
|
|
UpdateGetError("Not a valid number");
|
|
|
|
TriggerError("Not a valid number");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// float
|
|
|
|
// float
|
|
|
|
else if (typeof(T) == typeof(float) || typeof(T) == typeof(float?))
|
|
|
|
else if (typeof(T) == typeof(float) || typeof(T) == typeof(float?))
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if (float.TryParse(value, NumberStyles.Any, Culture, out var parsedValue))
|
|
|
|
if (float.TryParse(value, NumberStyles.Any, Culture, out var parsedValue))
|
|
|
|
return (T)(object)parsedValue;
|
|
|
|
return (T)(object)parsedValue;
|
|
|
|
UpdateGetError("Not a valid number");
|
|
|
|
TriggerError("Not a valid number");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// double
|
|
|
|
// double
|
|
|
|
else if (typeof(T) == typeof(double) || typeof(T) == typeof(double?))
|
|
|
|
else if (typeof(T) == typeof(double) || typeof(T) == typeof(double?))
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if (double.TryParse(value, NumberStyles.Any, Culture, out var parsedValue))
|
|
|
|
if (double.TryParse(value, NumberStyles.Any, Culture, out var parsedValue))
|
|
|
|
return (T)(object)parsedValue;
|
|
|
|
return (T)(object)parsedValue;
|
|
|
|
UpdateGetError("Not a valid number");
|
|
|
|
TriggerError("Not a valid number");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// decimal
|
|
|
|
// decimal
|
|
|
|
else if (typeof(T) == typeof(decimal) || typeof(T) == typeof(decimal?))
|
|
|
|
else if (typeof(T) == typeof(decimal) || typeof(T) == typeof(decimal?))
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if (decimal.TryParse(value, NumberStyles.Any, Culture, out var parsedValue))
|
|
|
|
if (decimal.TryParse(value, NumberStyles.Any, Culture, out var parsedValue))
|
|
|
|
return (T)(object)parsedValue;
|
|
|
|
return (T)(object)parsedValue;
|
|
|
|
UpdateGetError("Not a valid number");
|
|
|
|
TriggerError("Not a valid number");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// guid
|
|
|
|
// guid
|
|
|
|
else if (typeof(T) == typeof(Guid) || typeof(T) == typeof(Guid?))
|
|
|
|
else if (typeof(T) == typeof(Guid) || typeof(T) == typeof(Guid?))
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if (Guid.TryParse(value, out var parsedValue))
|
|
|
|
if (Guid.TryParse(value, out var parsedValue))
|
|
|
|
return (T)(object)parsedValue;
|
|
|
|
return (T)(object)parsedValue;
|
|
|
|
UpdateGetError("Not a valid GUID");
|
|
|
|
TriggerError("Not a valid GUID");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// enum
|
|
|
|
// enum
|
|
|
|
else if (IsNullableEnum(typeof(T)))
|
|
|
|
else if (IsNullableEnum(typeof(T)))
|
|
|
@ -134,13 +142,13 @@ namespace Connected
|
|
|
|
var enum_type = Nullable.GetUnderlyingType(typeof(T));
|
|
|
|
var enum_type = Nullable.GetUnderlyingType(typeof(T));
|
|
|
|
if (Enum.TryParse(enum_type, value, out var parsedValue))
|
|
|
|
if (Enum.TryParse(enum_type, value, out var parsedValue))
|
|
|
|
return (T)parsedValue;
|
|
|
|
return (T)parsedValue;
|
|
|
|
UpdateGetError("Not a value of " + enum_type.Name);
|
|
|
|
TriggerError("Not a value of " + enum_type.Name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (typeof(T).IsEnum)
|
|
|
|
else if (typeof(T).IsEnum)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if (Enum.TryParse(typeof(T), value, out var parsedValue))
|
|
|
|
if (Enum.TryParse(typeof(T), value, out var parsedValue))
|
|
|
|
return (T)parsedValue;
|
|
|
|
return (T)parsedValue;
|
|
|
|
UpdateGetError("Not a value of " + typeof(T).Name);
|
|
|
|
TriggerError("Not a value of " + typeof(T).Name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// datetime
|
|
|
|
// datetime
|
|
|
|
else if (typeof(T) == typeof(DateTime) || typeof(T) == typeof(DateTime?))
|
|
|
|
else if (typeof(T) == typeof(DateTime) || typeof(T) == typeof(DateTime?))
|
|
|
@ -151,7 +159,7 @@ namespace Connected
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (FormatException)
|
|
|
|
catch (FormatException)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
UpdateGetError("Not a valid date time");
|
|
|
|
TriggerError("Not a valid date time");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// timespan
|
|
|
|
// timespan
|
|
|
@ -163,17 +171,17 @@ namespace Connected
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (FormatException)
|
|
|
|
catch (FormatException)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
UpdateGetError("Not a valid time span");
|
|
|
|
TriggerError("Not a valid time span");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
else
|
|
|
|
{
|
|
|
|
{
|
|
|
|
UpdateGetError($"Conversion to type {typeof(T)} not implemented");
|
|
|
|
TriggerError($"Conversion to type {typeof(T)} not implemented");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (Exception e)
|
|
|
|
catch (Exception e)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
UpdateGetError("Conversion error: " + e.Message);
|
|
|
|
TriggerError("Conversion error: " + e.Message);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return default(T);
|
|
|
|
return default(T);
|
|
|
@ -301,7 +309,7 @@ namespace Connected
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (FormatException e)
|
|
|
|
catch (FormatException e)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
UpdateSetError("Conversion error: " + e.Message);
|
|
|
|
TriggerError("Conversion error: " + e.Message);
|
|
|
|
return null;
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|