diff --git a/src/Avalonia.Diagnostics/Diagnostics/Views/PropertyValueEditorView.cs b/src/Avalonia.Diagnostics/Diagnostics/Views/PropertyValueEditorView.cs index 2ac228ae4d..01ddf82c1e 100644 --- a/src/Avalonia.Diagnostics/Diagnostics/Views/PropertyValueEditorView.cs +++ b/src/Avalonia.Diagnostics/Diagnostics/Views/PropertyValueEditorView.cs @@ -57,42 +57,11 @@ namespace Avalonia.Diagnostics.Views if (Property?.PropertyType is not { } propertyType) return null; - TControl CreateControl(AvaloniaProperty valueProperty, - IValueConverter? converter = null, - Action? init = null, - AvaloniaProperty? readonlyProperty = null) - where TControl : Control, new() - { - var control = new TControl(); - var bindingMode = Property.IsReadonly ? BindingMode.OneWay : BindingMode.TwoWay; - - init?.Invoke(control); - - control.Bind(valueProperty, - new Binding(nameof(Property.Value), bindingMode) - { - Source = Property, - Converter = converter ?? new ValueConverter(), - ConverterParameter = readonlyProperty?.Name ?? valueProperty.Name, - }).DisposeWith(_cleanup); - - if (readonlyProperty != null) - { - control[readonlyProperty] = Property.IsReadonly; - } - else - { - control.IsEnabled = !Property.IsReadonly; - } - - return control; - } - if (propertyType == typeof(bool)) return CreateControl(ToggleButton.IsCheckedProperty); //TODO: Infinity, NaN not working with NumericUpDown - if (propertyType.IsPrimitive && propertyType != typeof(float) && propertyType != typeof(double)) + if (IsValidNumeric(propertyType)) return CreateControl( NumericUpDown.ValueProperty, new ValueToDecimalConverter(), @@ -139,7 +108,8 @@ namespace Avalonia.Diagnostics.Views ColorView.ColorProperty, new Binding(nameof(Property.Value), BindingMode.TwoWay) { - Source = Property, Converter = Color2Brush + Source = Property, + Converter = Color2Brush }) .DisposeWith(_cleanup); @@ -261,6 +231,74 @@ namespace Avalonia.Diagnostics.Views } return tb; + + TControl CreateControl(AvaloniaProperty valueProperty + , IValueConverter? converter = null + , Action? init = null + , AvaloniaProperty? readonlyProperty = null) + where TControl : Control, new() + { + var control = new TControl(); + var bindingMode = Property.IsReadonly ? BindingMode.OneWay : BindingMode.TwoWay; + + init?.Invoke(control); + + control.Bind(valueProperty, + new Binding(nameof(Property.Value), bindingMode) + { + Source = Property, + Converter = converter ?? new ValueConverter(), + ConverterParameter = propertyType + }).DisposeWith(_cleanup); + + if (readonlyProperty != null) + { + control[readonlyProperty] = Property.IsReadonly; + } + else + { + control.IsEnabled = !Property.IsReadonly; + } + + return control; + } + + static bool IsValidNumeric(Type? type) + { + if (type == null) + { + return false; + } + var typeCode = Type.GetTypeCode(type); + if (typeCode == TypeCode.Object) + { + if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)) + { + typeCode = Type.GetTypeCode(Nullable.GetUnderlyingType(type)); + } + else + { + return false; + } + } + switch (typeCode) + { + case TypeCode.Byte: + case TypeCode.Int16: + case TypeCode.Int32: + case TypeCode.Int64: + case TypeCode.SByte: + case TypeCode.Single: + case TypeCode.UInt16: + case TypeCode.UInt32: + case TypeCode.UInt64: + return true; + default: + return false; + } + } + + } //HACK: ValueConverter that skips first target update