[WIP] Refactor default converters
This commit is contained in:
		
							parent
							
								
									82594cff34
								
							
						
					
					
						commit
						2daf5b6c1e
					
				@ -11,11 +11,19 @@ namespace Connected
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        public BoolConverter()
 | 
					        public BoolConverter()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            SetFunc = OnSet;
 | 
					 | 
				
			||||||
            GetFunc = OnGet;
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private T OnGet(bool? value)
 | 
							protected override bool? ConvertValue(T? value)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
					            return OnSet(value);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							protected override T? ConvertValueBack(bool? value)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return OnGet(value);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							private T OnGet(bool? value)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            try
 | 
					            try
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
@ -31,12 +39,12 @@ namespace Connected
 | 
				
			|||||||
                    return (T)(object)(value == true ? 1 : (value == false ? (int?)0 : null));
 | 
					                    return (T)(object)(value == true ? 1 : (value == false ? (int?)0 : null));
 | 
				
			||||||
                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);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            return default(T);
 | 
					            return default(T);
 | 
				
			||||||
@ -69,13 +77,13 @@ namespace Connected
 | 
				
			|||||||
                }
 | 
					                }
 | 
				
			||||||
                else
 | 
					                else
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    UpdateSetError("Unable to convert to bool? from type " + typeof(T).Name);
 | 
					                    TriggerError("Unable to convert to bool? from type " + typeof(T).Name);
 | 
				
			||||||
                    return null;
 | 
					                    return null;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            catch (FormatException e)
 | 
					            catch (FormatException e)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                UpdateSetError("Conversion error: " + e.Message);
 | 
					                TriggerError("Conversion error: " + e.Message);
 | 
				
			||||||
                return null;
 | 
					                return null;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
				
			|||||||
@ -1,88 +1,111 @@
 | 
				
			|||||||
using System;
 | 
					using System.Globalization;
 | 
				
			||||||
using System.Globalization;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Connected
 | 
					namespace Connected;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class Converter<TSourceType, TDestinationType>
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    public class Converter<T, U>
 | 
					    public event EventHandler<string?>? ErrorOccured;
 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        public Func<T, U> SetFunc { get; set; }
 | 
					 | 
				
			||||||
        public Func<U, T> GetFunc { get; set; }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        /// <summary>
 | 
					 | 
				
			||||||
        /// The culture info being used for decimal points, date and time format, etc.
 | 
					 | 
				
			||||||
        /// </summary>
 | 
					 | 
				
			||||||
        public CultureInfo Culture { get; set; } = Converters.DefaultCulture;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public Action<string> OnError { get; set; }
 | 
					 | 
				
			||||||
        public bool SetError { get; set; }
 | 
					 | 
				
			||||||
        public bool GetError { get; set; }
 | 
					 | 
				
			||||||
        public string SetErrorMessage { get; set; }
 | 
					 | 
				
			||||||
        public string GetErrorMessage { get; set; }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public U Set(T value)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            SetError = false;
 | 
					 | 
				
			||||||
            SetErrorMessage = null;
 | 
					 | 
				
			||||||
            if (SetFunc == null)
 | 
					 | 
				
			||||||
                return default(U);
 | 
					 | 
				
			||||||
            try
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                return SetFunc(value);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            catch (Exception e)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                SetError = true;
 | 
					 | 
				
			||||||
                SetErrorMessage = $"Conversion from {typeof(T).Name} to {typeof(U).Name} failed: {e.Message}";
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            return default(U);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        public T Get(U value)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            GetError = false;
 | 
					 | 
				
			||||||
            GetErrorMessage = null;
 | 
					 | 
				
			||||||
            if (GetFunc == null)
 | 
					 | 
				
			||||||
                return default(T);
 | 
					 | 
				
			||||||
            try
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                return GetFunc(value);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            catch (Exception e)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                GetError = true;
 | 
					 | 
				
			||||||
                GetErrorMessage = $"Conversion from {typeof(U).Name} to {typeof(T).Name} failed: {e.Message}";
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            return default(T);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        protected void UpdateSetError(string msg)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            SetError = true;
 | 
					 | 
				
			||||||
            SetErrorMessage = msg;
 | 
					 | 
				
			||||||
            OnError?.Invoke(msg);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        protected void UpdateGetError(string msg)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            GetError = true;
 | 
					 | 
				
			||||||
            GetErrorMessage = msg;
 | 
					 | 
				
			||||||
            OnError?.Invoke(msg);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// Converter from T to string
 | 
					    /// The culture info being used for decimal points, date and time format, etc.
 | 
				
			||||||
    ///
 | 
					 | 
				
			||||||
    /// Set converts to string
 | 
					 | 
				
			||||||
    /// Get converts from string
 | 
					 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    public class Converter<T> : Converter<T, string>
 | 
					    public CultureInfo Culture { get; set; } = Converters.DefaultCulture;
 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /// <summary>
 | 
					    public TDestinationType? Convert(TSourceType value)
 | 
				
			||||||
        /// Custom Format to be applied on bidirectional way.
 | 
					    {
 | 
				
			||||||
        /// </summary>
 | 
					        try
 | 
				
			||||||
        public string Format { get; set; } = null;
 | 
					        {
 | 
				
			||||||
 | 
					            return ConvertValue(value);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        catch (Exception e)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            TriggerError($"Conversion from {typeof(TSourceType).Name} to {typeof(TDestinationType).Name} failed: {e.Message}", e);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return default;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected virtual TDestinationType? ConvertValue(TSourceType? value)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return default;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public TSourceType? ConvertBack(TDestinationType value)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        try
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return ConvertValueBack(value);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        catch (Exception e)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            TriggerError($"Conversion from {typeof(TDestinationType).Name} to {typeof(TSourceType).Name} failed: {e.Message}", e);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return default;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected virtual TSourceType? ConvertValueBack(TDestinationType? value)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return default;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected void TriggerError(string? msg, Exception? e = null)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        ErrorOccured?.Invoke(this, msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        OnErrorOccured(msg, e);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected virtual void OnErrorOccured(string? msg, Exception? e)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// <summary>
 | 
				
			||||||
 | 
					/// Converts values using the supplied lambda functions.
 | 
				
			||||||
 | 
					/// </summary>
 | 
				
			||||||
 | 
					/// <typeparam name="TSourceType">The source type</typeparam>
 | 
				
			||||||
 | 
					/// <typeparam name="TDestinationType">The destination type</typeparam>
 | 
				
			||||||
 | 
					public class LambdaConverter<TSourceType, TDestinationType> :Converter<TSourceType, TDestinationType>
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    private readonly Func<TSourceType, TDestinationType?>? _convertFunction;
 | 
				
			||||||
 | 
					    private readonly Func<TDestinationType, TSourceType?>? _convertBackFunction;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public LambdaConverter(Func<TSourceType, TDestinationType?>? convertFunction = null, Func<TDestinationType, TSourceType?>? convertBackFunction = null) 
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        _convertFunction = convertFunction;
 | 
				
			||||||
 | 
					        _convertBackFunction = convertBackFunction;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected override TDestinationType? ConvertValue(TSourceType? value)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (_convertFunction is null)
 | 
				
			||||||
 | 
					            return base.ConvertValue(value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return _convertFunction.Invoke(value);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected override TSourceType? ConvertValueBack(TDestinationType? value)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (_convertFunction is null)
 | 
				
			||||||
 | 
					            return base.ConvertValueBack(value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return _convertBackFunction.Invoke(value);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// <summary>
 | 
				
			||||||
 | 
					/// Converter from T to string
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// Set converts to string
 | 
				
			||||||
 | 
					/// Get converts from string
 | 
				
			||||||
 | 
					/// </summary>
 | 
				
			||||||
 | 
					public class ToStringConverter<T> : Converter<T, string>
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    /// Custom Format to be applied on bidirectional way.
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    public string? Format { get; set; } = null;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,4 +1,5 @@
 | 
				
			|||||||
using System.Globalization;
 | 
					using Connected.Extensions;
 | 
				
			||||||
 | 
					using System.Globalization;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Connected
 | 
					namespace Connected
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@ -7,9 +8,8 @@ namespace Connected
 | 
				
			|||||||
      public static CultureInfo DefaultCulture = CultureInfo.CurrentUICulture;
 | 
					      public static CultureInfo DefaultCulture = CultureInfo.CurrentUICulture;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      #region --> Date converters
 | 
					      #region --> Date converters
 | 
				
			||||||
      public static Converter<DateTime> IsoDate
 | 
					      public static LambdaConverter<DateTime, string> IsoDate
 | 
				
			||||||
          => new()
 | 
					          => new(SetIsoDate, GetIsoDate);
 | 
				
			||||||
          { SetFunc = SetIsoDate, GetFunc = GetIsoDate };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
      private static DateTime GetIsoDate(string value)
 | 
					      private static DateTime GetIsoDate(string value)
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
@ -23,11 +23,10 @@ namespace Connected
 | 
				
			|||||||
         return value.ToIsoDateString();
 | 
					         return value.ToIsoDateString();
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      public static Converter<DateTime?> NullableIsoDate
 | 
					        public static LambdaConverter<DateTime?, string?> NullableIsoDate
 | 
				
			||||||
          => new()
 | 
					            => new(SetNullableIsoDate, GetNullableIsoDate);
 | 
				
			||||||
          { SetFunc = SetNullableIsoDate, GetFunc = GetNullableIsoDate };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
      private static DateTime? GetNullableIsoDate(string value)
 | 
					      private static DateTime? GetNullableIsoDate(string? value)
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
         if (DateTime.TryParse(value, out var dateTime))
 | 
					         if (DateTime.TryParse(value, out var dateTime))
 | 
				
			||||||
            return dateTime;
 | 
					            return dateTime;
 | 
				
			||||||
 | 
				
			|||||||
@ -6,18 +6,26 @@ namespace Connected
 | 
				
			|||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// A ready made DateTime? to string binding converter with configurable date format and culture
 | 
					    /// A ready made DateTime? to string binding converter with configurable date format and culture
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    public class NullableDateConverter : Converter<DateTime?>
 | 
					    public class NullableDateConverter : ToStringConverter<DateTime?>
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        public string DateFormat { get; set; }
 | 
					        public string DateFormat { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public NullableDateConverter(string format = "yyyy-MM-dd")
 | 
					        public NullableDateConverter(string format = "yyyy-MM-dd")
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            DateFormat = format;
 | 
					            DateFormat = format;
 | 
				
			||||||
            SetFunc = OnSet;
 | 
					 | 
				
			||||||
            GetFunc = OnGet;
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private DateTime? OnGet(string arg)
 | 
							protected override string? ConvertValue(DateTime? value)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
					            return OnSet(value);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							protected override DateTime? ConvertValueBack(string? value)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
					            return OnGet(value);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							private DateTime? OnGet(string arg)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            try
 | 
					            try
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
@ -25,7 +33,7 @@ namespace Connected
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
            catch (FormatException e)
 | 
					            catch (FormatException e)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                UpdateGetError(e.Message);
 | 
					                TriggerError(e.Message);
 | 
				
			||||||
                return null;
 | 
					                return null;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@ -40,7 +48,7 @@ namespace Connected
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
            catch (FormatException e)
 | 
					            catch (FormatException e)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                UpdateSetError(e.Message);
 | 
					                TriggerError(e.Message);
 | 
				
			||||||
                return null;
 | 
					                return null;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@ -49,18 +57,26 @@ namespace Connected
 | 
				
			|||||||
    /// <summary>
 | 
					    /// <summary>
 | 
				
			||||||
    /// A ready made DateTime to string binding converter with configurable date format and culture
 | 
					    /// A ready made DateTime to string binding converter with configurable date format and culture
 | 
				
			||||||
    /// </summary>
 | 
					    /// </summary>
 | 
				
			||||||
    public class DateConverter : Converter<DateTime>
 | 
					    public class DateConverter : ToStringConverter<DateTime>
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        public string DateFormat { get; set; } = "yyyy-MM-dd";
 | 
					        public string DateFormat { get; set; } = "yyyy-MM-dd";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public DateConverter(string format)
 | 
					        public DateConverter(string format)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            DateFormat = format;
 | 
					            DateFormat = format;
 | 
				
			||||||
            SetFunc = OnSet;
 | 
					 | 
				
			||||||
            GetFunc = OnGet;
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private DateTime OnGet(string arg)
 | 
							protected override string? ConvertValue(DateTime value)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return OnSet(value);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							protected override DateTime ConvertValueBack(string value)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return OnGet(value);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							private DateTime OnGet(string arg)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            try
 | 
					            try
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
@ -68,7 +84,7 @@ namespace Connected
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
            catch (FormatException e)
 | 
					            catch (FormatException e)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                UpdateGetError(e.Message);
 | 
					                TriggerError(e.Message);
 | 
				
			||||||
                return default;
 | 
					                return default;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@ -81,7 +97,7 @@ namespace Connected
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
            catch (FormatException e)
 | 
					            catch (FormatException e)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                UpdateSetError(e.Message);
 | 
					                TriggerError(e.Message);
 | 
				
			||||||
                return null;
 | 
					                return null;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
				
			|||||||
@ -7,16 +7,24 @@ 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;
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public string DefaultTimeSpanFormat { get; set; } = "c";
 | 
							  protected override string? ConvertValue(T? value)
 | 
				
			||||||
 | 
							  {
 | 
				
			||||||
 | 
					            return ConvertToString(value);
 | 
				
			||||||
 | 
							  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							  protected override T? ConvertValueBack(string? value)
 | 
				
			||||||
 | 
							  {
 | 
				
			||||||
 | 
									return ConvertFromString(value);
 | 
				
			||||||
 | 
							  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							  public string DefaultTimeSpanFormat { get; set; } = "c";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        protected virtual T ConvertFromString(string value)
 | 
					        protected virtual T ConvertFromString(string value)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
@ -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;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
				
			|||||||
@ -17,11 +17,19 @@ namespace Connected
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        public NumericConverter()
 | 
					        public NumericConverter()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            SetFunc = OnSet;
 | 
					 | 
				
			||||||
            GetFunc = OnGet;
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private T OnGet(double value)
 | 
							protected override double ConvertValue(T? value)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return OnSet(value);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							protected override T? ConvertValueBack(double value)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return OnGet(value);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							private T OnGet(double value)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            try
 | 
					            try
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
@ -33,42 +41,42 @@ namespace Connected
 | 
				
			|||||||
                    return (T)(object)value.ToString(Culture);
 | 
					                    return (T)(object)value.ToString(Culture);
 | 
				
			||||||
                // sbyte
 | 
					                // sbyte
 | 
				
			||||||
                else if (typeof(T) == typeof(sbyte) || typeof(T) == typeof(sbyte?))
 | 
					                else if (typeof(T) == typeof(sbyte) || typeof(T) == typeof(sbyte?))
 | 
				
			||||||
                    return (T)(object)Convert.ToSByte(value);
 | 
					                    return (T)(object)System.Convert.ToSByte(value);
 | 
				
			||||||
                // byte
 | 
					                // byte
 | 
				
			||||||
                else if (typeof(T) == typeof(byte) || typeof(T) == typeof(byte?))
 | 
					                else if (typeof(T) == typeof(byte) || typeof(T) == typeof(byte?))
 | 
				
			||||||
                    return (T)(object)Convert.ToByte(value);
 | 
					                    return (T)(object)System.Convert.ToByte(value);
 | 
				
			||||||
                // short
 | 
					                // short
 | 
				
			||||||
                else if (typeof(T) == typeof(short) || typeof(T) == typeof(short?))
 | 
					                else if (typeof(T) == typeof(short) || typeof(T) == typeof(short?))
 | 
				
			||||||
                    return (T)(object)Convert.ToInt16(value);
 | 
					                    return (T)(object)System.Convert.ToInt16(value);
 | 
				
			||||||
                // ushort
 | 
					                // ushort
 | 
				
			||||||
                else if (typeof(T) == typeof(ushort) || typeof(T) == typeof(ushort?))
 | 
					                else if (typeof(T) == typeof(ushort) || typeof(T) == typeof(ushort?))
 | 
				
			||||||
                    return (T)(object)Convert.ToUInt16(value);
 | 
					                    return (T)(object)System.Convert.ToUInt16(value);
 | 
				
			||||||
                // int
 | 
					                // int
 | 
				
			||||||
                else if (typeof(T) == typeof(int) || typeof(T) == typeof(int?))
 | 
					                else if (typeof(T) == typeof(int) || typeof(T) == typeof(int?))
 | 
				
			||||||
                    return (T)(object)Convert.ToInt32(value);
 | 
					                    return (T)(object)System.Convert.ToInt32(value);
 | 
				
			||||||
                // uint
 | 
					                // uint
 | 
				
			||||||
                else if (typeof(T) == typeof(uint) || typeof(T) == typeof(uint?))
 | 
					                else if (typeof(T) == typeof(uint) || typeof(T) == typeof(uint?))
 | 
				
			||||||
                    return (T)(object)Convert.ToUInt32(value);
 | 
					                    return (T)(object)System.Convert.ToUInt32(value);
 | 
				
			||||||
                // long
 | 
					                // long
 | 
				
			||||||
                else if (typeof(T) == typeof(long) || typeof(T) == typeof(long?))
 | 
					                else if (typeof(T) == typeof(long) || typeof(T) == typeof(long?))
 | 
				
			||||||
                    return (T)(object)Convert.ToInt64(value);
 | 
					                    return (T)(object)System.Convert.ToInt64(value);
 | 
				
			||||||
                // ulong
 | 
					                // ulong
 | 
				
			||||||
                else if (typeof(T) == typeof(ulong) || typeof(T) == typeof(ulong?))
 | 
					                else if (typeof(T) == typeof(ulong) || typeof(T) == typeof(ulong?))
 | 
				
			||||||
                    return (T)(object)Convert.ToUInt64(value);
 | 
					                    return (T)(object)System.Convert.ToUInt64(value);
 | 
				
			||||||
                // float
 | 
					                // float
 | 
				
			||||||
                else if (typeof(T) == typeof(float) || typeof(T) == typeof(float?))
 | 
					                else if (typeof(T) == typeof(float) || typeof(T) == typeof(float?))
 | 
				
			||||||
                    return (T)(object)Convert.ToSingle(value);
 | 
					                    return (T)(object)System.Convert.ToSingle(value);
 | 
				
			||||||
                // decimal
 | 
					                // decimal
 | 
				
			||||||
                else if (typeof(T) == typeof(decimal) || typeof(T) == typeof(decimal?))
 | 
					                else if (typeof(T) == typeof(decimal) || typeof(T) == typeof(decimal?))
 | 
				
			||||||
                    return (T)(object)Convert.ToDecimal(value);
 | 
					                    return (T)(object)System.Convert.ToDecimal(value);
 | 
				
			||||||
                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);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            return default(T);
 | 
					            return default(T);
 | 
				
			||||||
@ -90,63 +98,63 @@ namespace Connected
 | 
				
			|||||||
                    return double.Parse((string)(object)arg, NumberStyles.Any, Culture);
 | 
					                    return double.Parse((string)(object)arg, NumberStyles.Any, Culture);
 | 
				
			||||||
                // sbyte
 | 
					                // sbyte
 | 
				
			||||||
                if (typeof(T) == typeof(sbyte))
 | 
					                if (typeof(T) == typeof(sbyte))
 | 
				
			||||||
                    return Convert.ToDouble((sbyte)(object)arg);
 | 
					                    return System.Convert.ToDouble((sbyte)(object)arg);
 | 
				
			||||||
                if (typeof(T) == typeof(sbyte?))
 | 
					                if (typeof(T) == typeof(sbyte?))
 | 
				
			||||||
                    return Convert.ToDouble(((sbyte?)(object)arg).Value);
 | 
					                    return System.Convert.ToDouble(((sbyte?)(object)arg).Value);
 | 
				
			||||||
                // byte
 | 
					                // byte
 | 
				
			||||||
                if (typeof(T) == typeof(byte))
 | 
					                if (typeof(T) == typeof(byte))
 | 
				
			||||||
                    return Convert.ToDouble((byte)(object)arg);
 | 
					                    return System.Convert.ToDouble((byte)(object)arg);
 | 
				
			||||||
                if (typeof(T) == typeof(byte?))
 | 
					                if (typeof(T) == typeof(byte?))
 | 
				
			||||||
                    return Convert.ToDouble(((byte?)(object)arg).Value);
 | 
					                    return System.Convert.ToDouble(((byte?)(object)arg).Value);
 | 
				
			||||||
                // short
 | 
					                // short
 | 
				
			||||||
                if (typeof(T) == typeof(short))
 | 
					                if (typeof(T) == typeof(short))
 | 
				
			||||||
                    return Convert.ToDouble((short)(object)arg);
 | 
					                    return System.Convert.ToDouble((short)(object)arg);
 | 
				
			||||||
                if (typeof(T) == typeof(short?))
 | 
					                if (typeof(T) == typeof(short?))
 | 
				
			||||||
                    return Convert.ToDouble(((short?)(object)arg).Value);
 | 
					                    return System.Convert.ToDouble(((short?)(object)arg).Value);
 | 
				
			||||||
                // ushort
 | 
					                // ushort
 | 
				
			||||||
                if (typeof(T) == typeof(ushort))
 | 
					                if (typeof(T) == typeof(ushort))
 | 
				
			||||||
                    return Convert.ToDouble((ushort)(object)arg);
 | 
					                    return System.Convert.ToDouble((ushort)(object)arg);
 | 
				
			||||||
                if (typeof(T) == typeof(ushort?))
 | 
					                if (typeof(T) == typeof(ushort?))
 | 
				
			||||||
                    return Convert.ToDouble(((ushort?)(object)arg).Value);
 | 
					                    return System.Convert.ToDouble(((ushort?)(object)arg).Value);
 | 
				
			||||||
                // int
 | 
					                // int
 | 
				
			||||||
                else if (typeof(T) == typeof(int))
 | 
					                else if (typeof(T) == typeof(int))
 | 
				
			||||||
                    return Convert.ToDouble((int)(object)arg);
 | 
					                    return System.Convert.ToDouble((int)(object)arg);
 | 
				
			||||||
                else if (typeof(T) == typeof(int?))
 | 
					                else if (typeof(T) == typeof(int?))
 | 
				
			||||||
                    return Convert.ToDouble(((int?)(object)arg).Value);
 | 
					                    return System.Convert.ToDouble(((int?)(object)arg).Value);
 | 
				
			||||||
                // uint
 | 
					                // uint
 | 
				
			||||||
                else if (typeof(T) == typeof(uint))
 | 
					                else if (typeof(T) == typeof(uint))
 | 
				
			||||||
                    return Convert.ToDouble((uint)(object)arg);
 | 
					                    return System.Convert.ToDouble((uint)(object)arg);
 | 
				
			||||||
                else if (typeof(T) == typeof(uint?))
 | 
					                else if (typeof(T) == typeof(uint?))
 | 
				
			||||||
                    return Convert.ToDouble(((uint?)(object)arg).Value);
 | 
					                    return System.Convert.ToDouble(((uint?)(object)arg).Value);
 | 
				
			||||||
                // long
 | 
					                // long
 | 
				
			||||||
                else if (typeof(T) == typeof(long))
 | 
					                else if (typeof(T) == typeof(long))
 | 
				
			||||||
                    return Convert.ToDouble((long)(object)arg);
 | 
					                    return System.Convert.ToDouble((long)(object)arg);
 | 
				
			||||||
                else if (typeof(T) == typeof(long?))
 | 
					                else if (typeof(T) == typeof(long?))
 | 
				
			||||||
                    return Convert.ToDouble(((long?)(object)arg).Value);
 | 
					                    return System.Convert.ToDouble(((long?)(object)arg).Value);
 | 
				
			||||||
                // ulong
 | 
					                // ulong
 | 
				
			||||||
                else if (typeof(T) == typeof(ulong))
 | 
					                else if (typeof(T) == typeof(ulong))
 | 
				
			||||||
                    return Convert.ToDouble((ulong)(object)arg);
 | 
					                    return System.Convert.ToDouble((ulong)(object)arg);
 | 
				
			||||||
                else if (typeof(T) == typeof(ulong?))
 | 
					                else if (typeof(T) == typeof(ulong?))
 | 
				
			||||||
                    return Convert.ToDouble(((ulong?)(object)arg).Value);
 | 
					                    return System.Convert.ToDouble(((ulong?)(object)arg).Value);
 | 
				
			||||||
                // float
 | 
					                // float
 | 
				
			||||||
                else if (typeof(T) == typeof(float))
 | 
					                else if (typeof(T) == typeof(float))
 | 
				
			||||||
                    return Convert.ToDouble((float)(object)arg);
 | 
					                    return System.Convert.ToDouble((float)(object)arg);
 | 
				
			||||||
                else if (typeof(T) == typeof(float?))
 | 
					                else if (typeof(T) == typeof(float?))
 | 
				
			||||||
                    return Convert.ToDouble(((float?)(object)arg).Value);
 | 
					                    return System.Convert.ToDouble(((float?)(object)arg).Value);
 | 
				
			||||||
                // decimal
 | 
					                // decimal
 | 
				
			||||||
                else if (typeof(T) == typeof(decimal))
 | 
					                else if (typeof(T) == typeof(decimal))
 | 
				
			||||||
                    return Convert.ToDouble((decimal)(object)arg);
 | 
					                    return System.Convert.ToDouble((decimal)(object)arg);
 | 
				
			||||||
                else if (typeof(T) == typeof(decimal?))
 | 
					                else if (typeof(T) == typeof(decimal?))
 | 
				
			||||||
                    return Convert.ToDouble(((decimal?)(object)arg).Value);
 | 
					                    return System.Convert.ToDouble(((decimal?)(object)arg).Value);
 | 
				
			||||||
                else
 | 
					                else
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    UpdateSetError("Unable to convert to double from type " + typeof(T).Name);
 | 
					                    TriggerError("Unable to convert to double from type " + typeof(T).Name);
 | 
				
			||||||
                    return double.NaN;
 | 
					                    return double.NaN;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            catch (FormatException e)
 | 
					            catch (FormatException e)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                UpdateSetError("Conversion error: " + e.Message);
 | 
					                TriggerError("Conversion error: " + e.Message);
 | 
				
			||||||
                return double.NaN;
 | 
					                return double.NaN;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
				
			|||||||
@ -1,61 +1,69 @@
 | 
				
			|||||||
namespace Connected
 | 
					using Connected.Components;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Connected;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class RangeConverter<T> : ToStringConverter<Range<T>>
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
   public class RangeConverter<T> : Converter<Components.Range<T>>
 | 
						readonly DefaultConverter<T> _converter;
 | 
				
			||||||
   {
 | 
					 | 
				
			||||||
      readonly DefaultConverter<T> _converter;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
      public RangeConverter()
 | 
						public RangeConverter()
 | 
				
			||||||
      {
 | 
						{
 | 
				
			||||||
         _converter = new DefaultConverter<T>();
 | 
							_converter = new DefaultConverter<T>();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
         SetFunc = OnSet;
 | 
						protected override string? ConvertValue(Range<T>? value)
 | 
				
			||||||
         GetFunc = OnGet;
 | 
						{
 | 
				
			||||||
      }
 | 
							return OnSet(value);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      private Components.Range<T> OnGet(string value)
 | 
						protected override Range<T>? ConvertValueBack(string? value)
 | 
				
			||||||
      {
 | 
						{
 | 
				
			||||||
         if (!Split(value, out var valueStart, out var valueEnd))
 | 
							return OnGet(value);
 | 
				
			||||||
            return null;
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
         return new Components.Range<T>(_converter.Get(valueStart), _converter.Get(valueEnd));
 | 
						private Range<T> OnGet(string value)
 | 
				
			||||||
      }
 | 
						{
 | 
				
			||||||
 | 
							if (!Split(value, out var valueStart, out var valueEnd))
 | 
				
			||||||
 | 
								return null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      private string OnSet(Components.Range<T> arg)
 | 
							return new Range<T>(_converter.ConvertBack(valueStart), _converter.ConvertBack(valueEnd));
 | 
				
			||||||
      {
 | 
						}
 | 
				
			||||||
         if (arg == null)
 | 
					 | 
				
			||||||
            return string.Empty;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
         return Join(_converter.Set(arg.Start), _converter.Set(arg.End));
 | 
						private string OnSet(Range<T> arg)
 | 
				
			||||||
      }
 | 
						{
 | 
				
			||||||
 | 
							if (arg == null)
 | 
				
			||||||
 | 
								return string.Empty;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      public static string Join(string valueStart, string valueEnd)
 | 
							return Join(_converter.Convert(arg.Start), _converter.Convert(arg.End));
 | 
				
			||||||
      {
 | 
						}
 | 
				
			||||||
         if (string.IsNullOrEmpty(valueStart) && string.IsNullOrEmpty(valueEnd))
 | 
					 | 
				
			||||||
            return string.Empty;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
         return $"[{valueStart};{valueEnd}]";
 | 
						public static string Join(string valueStart, string valueEnd)
 | 
				
			||||||
      }
 | 
						{
 | 
				
			||||||
 | 
							if (string.IsNullOrEmpty(valueStart) && string.IsNullOrEmpty(valueEnd))
 | 
				
			||||||
 | 
								return string.Empty;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      public static bool Split(string value, out string valueStart, out string valueEnd)
 | 
							return $"[{valueStart};{valueEnd}]";
 | 
				
			||||||
      {
 | 
						}
 | 
				
			||||||
         valueStart = valueEnd = string.Empty;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
         if (string.IsNullOrEmpty(value) || value[0] != '[' || value[^1] != ']')
 | 
						public static bool Split(string value, out string valueStart, out string valueEnd)
 | 
				
			||||||
         {
 | 
						{
 | 
				
			||||||
            return false;
 | 
							valueStart = valueEnd = string.Empty;
 | 
				
			||||||
         }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
         var idx = value.IndexOf(';');
 | 
							if (string.IsNullOrEmpty(value) || value[0] != '[' || value[^1] != ']')
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
         if (idx < 1)
 | 
							var idx = value.IndexOf(';');
 | 
				
			||||||
         {
 | 
					 | 
				
			||||||
            return false;
 | 
					 | 
				
			||||||
         }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
         valueStart = value[1..idx];
 | 
							if (idx < 1)
 | 
				
			||||||
         valueEnd = value[(idx + 1)..^1];
 | 
							{
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
         return true;
 | 
							valueStart = value[1..idx];
 | 
				
			||||||
      }
 | 
							valueEnd = value[(idx + 1)..^1];
 | 
				
			||||||
   }
 | 
					
 | 
				
			||||||
 | 
							return true;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user