diff --git a/samples/BindingTest/MainWindow.xaml b/samples/BindingTest/MainWindow.xaml
index f0bb169f3c..02c364346d 100644
--- a/samples/BindingTest/MainWindow.xaml
+++ b/samples/BindingTest/MainWindow.xaml
@@ -82,6 +82,7 @@
+
diff --git a/samples/BindingTest/ViewModels/DataAnnotationsErrorViewModel.cs b/samples/BindingTest/ViewModels/DataAnnotationsErrorViewModel.cs
index b622ee9e18..634498c165 100644
--- a/samples/BindingTest/ViewModels/DataAnnotationsErrorViewModel.cs
+++ b/samples/BindingTest/ViewModels/DataAnnotationsErrorViewModel.cs
@@ -10,5 +10,8 @@ namespace BindingTest.ViewModels
[Phone]
[MaxLength(10)]
public string PhoneNumber { get; set; }
+
+ [Range(0, 9)]
+ public int LessThan10 { get; set; }
}
}
diff --git a/src/Avalonia.Base/AvaloniaObject.cs b/src/Avalonia.Base/AvaloniaObject.cs
index 0f2afc6474..eeaf782e83 100644
--- a/src/Avalonia.Base/AvaloniaObject.cs
+++ b/src/Avalonia.Base/AvaloniaObject.cs
@@ -667,7 +667,7 @@ namespace Avalonia
Logger.Error(
LogArea.Binding,
this,
- "Error binding to {Target}.{Property}: {Message}",
+ "Error in binding to {Target}.{Property}: {Message}",
this,
property,
ExceptionUtilities.GetMessage(notification.Error));
diff --git a/src/Avalonia.Base/PriorityValue.cs b/src/Avalonia.Base/PriorityValue.cs
index 11bd6c61cd..a7eb4465b3 100644
--- a/src/Avalonia.Base/PriorityValue.cs
+++ b/src/Avalonia.Base/PriorityValue.cs
@@ -189,7 +189,7 @@ namespace Avalonia
LogEventLevel.Error,
LogArea.Binding,
_owner,
- "Error binding to {Target}.{Property}: {Message}",
+ "Error in binding to {Target}.{Property}: {Message}",
_owner,
Property,
error.Error.Message);
diff --git a/src/Avalonia.Base/Utilities/TypeUtilities.cs b/src/Avalonia.Base/Utilities/TypeUtilities.cs
index 2d4c911933..7295bfa7ab 100644
--- a/src/Avalonia.Base/Utilities/TypeUtilities.cs
+++ b/src/Avalonia.Base/Utilities/TypeUtilities.cs
@@ -27,6 +27,21 @@ namespace Avalonia.Utilities
{ typeof(short), new List { typeof(byte) } }
};
+ private static readonly Type[] NumericTypes = new[]
+ {
+ typeof(Byte),
+ typeof(Decimal),
+ typeof(Double),
+ typeof(Int16),
+ typeof(Int32),
+ typeof(Int64),
+ typeof(SByte),
+ typeof(Single),
+ typeof(UInt16),
+ typeof(UInt32),
+ typeof(UInt64),
+ };
+
///
/// Returns a value indicating whether null can be assigned to the specified type.
///
@@ -208,5 +223,31 @@ namespace Avalonia.Utilities
return null;
}
}
+
+ ///
+ /// Determines if a type is numeric. Nullable numeric types are considered numeric.
+ ///
+ ///
+ /// True if the type is numberic; otherwise false.
+ ///
+ ///
+ /// Boolean is not considered numeric.
+ ///
+ public static bool IsNumeric(Type type)
+ {
+ if (type == null)
+ {
+ return false;
+ }
+
+ if (type.GetTypeInfo().IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
+ {
+ return IsNumeric(Nullable.GetUnderlyingType(type));
+ }
+ else
+ {
+ return NumericTypes.Contains(type);
+ }
+ }
}
}
diff --git a/src/Markup/Avalonia.Markup/Data/ExpressionSubject.cs b/src/Markup/Avalonia.Markup/Data/ExpressionSubject.cs
index 85609c247c..cb587c683b 100644
--- a/src/Markup/Avalonia.Markup/Data/ExpressionSubject.cs
+++ b/src/Markup/Avalonia.Markup/Data/ExpressionSubject.cs
@@ -139,9 +139,6 @@ namespace Avalonia.Markup.Data
"IValueConverter should not return non-errored BindingNotification.");
}
- notification.Error = new InvalidCastException(
- $"Error setting '{_inner.Expression}': {notification.Error.Message}");
- notification.ErrorType = BindingErrorType.Error;
_errors.OnNext(notification);
if (_fallbackValue != AvaloniaProperty.UnsetValue)
diff --git a/src/Markup/Avalonia.Markup/DefaultValueConverter.cs b/src/Markup/Avalonia.Markup/DefaultValueConverter.cs
index cde73b67a1..86d37d8e13 100644
--- a/src/Markup/Avalonia.Markup/DefaultValueConverter.cs
+++ b/src/Markup/Avalonia.Markup/DefaultValueConverter.cs
@@ -43,7 +43,17 @@ namespace Avalonia.Markup
if (value != null)
{
- var message = $"Could not convert '{value}' to '{targetType}'";
+ string message;
+
+ if (TypeUtilities.IsNumeric(targetType))
+ {
+ message = $"'{value}' is not a valid number.";
+ }
+ else
+ {
+ message = $"Could not convert '{value}' to '{targetType.Name}'.";
+ }
+
return new BindingNotification(new InvalidCastException(message), BindingErrorType.Error);
}
diff --git a/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Binding.cs b/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Binding.cs
index 1757550d4a..66fe3c7767 100644
--- a/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Binding.cs
+++ b/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Binding.cs
@@ -332,7 +332,7 @@ namespace Avalonia.Base.UnitTests
var target = new Class1();
var source = new Subject