From ff5f4804e2035602b0a7f7c306ef480c35a16581 Mon Sep 17 00:00:00 2001
From: usUyGBx <64971385+usUyGBx@users.noreply.github.com>
Date: Sun, 31 May 2020 22:04:24 +0300
Subject: [PATCH 1/3] Fix AutoCompleteBox validation
---
src/Avalonia.Controls/AutoCompleteBox.cs | 21 ++++++++++++++++++---
1 file changed, 18 insertions(+), 3 deletions(-)
diff --git a/src/Avalonia.Controls/AutoCompleteBox.cs b/src/Avalonia.Controls/AutoCompleteBox.cs
index 3e4f47ec8a..c62ad3030e 100644
--- a/src/Avalonia.Controls/AutoCompleteBox.cs
+++ b/src/Avalonia.Controls/AutoCompleteBox.cs
@@ -467,10 +467,11 @@ namespace Avalonia.Controls
///
/// dependency property.
public static readonly DirectProperty TextProperty =
- AvaloniaProperty.RegisterDirect(
- nameof(Text),
+ TextBlock.TextProperty.AddOwnerWithDataValidation(
o => o.Text,
- (o, v) => o.Text = v);
+ (o, v) => o.Text = v,
+ defaultBindingMode: BindingMode.TwoWay,
+ enableDataValidation: true);
///
/// Identifies the
@@ -1242,6 +1243,20 @@ namespace Avalonia.Controls
base.OnApplyTemplate(e);
}
+
+ ///
+ /// Called to update the validation state for properties for which data validation is
+ /// enabled.
+ ///
+ /// The property.
+ /// The new binding value for the property.
+ protected override void UpdateDataValidation(AvaloniaProperty property, BindingValue value)
+ {
+ if (property == TextProperty)
+ {
+ DataValidationErrors.SetError(this, value.Error);
+ }
+ }
///
/// Provides handling for the
From c3fca8325f34ed240069db256ce9081e13c0b20a Mon Sep 17 00:00:00 2001
From: Rustam Sayfutdinov
Date: Thu, 11 Jun 2020 20:21:07 +0300
Subject: [PATCH 2/3] Add math utilities to compare single precision
---
src/Avalonia.Base/Utilities/MathUtilities.cs | 85 ++++++++++++++++++++
1 file changed, 85 insertions(+)
diff --git a/src/Avalonia.Base/Utilities/MathUtilities.cs b/src/Avalonia.Base/Utilities/MathUtilities.cs
index 3fb5f7a162..7949a62949 100644
--- a/src/Avalonia.Base/Utilities/MathUtilities.cs
+++ b/src/Avalonia.Base/Utilities/MathUtilities.cs
@@ -11,6 +11,8 @@ namespace Avalonia.Utilities
// smallest such that 1.0+DoubleEpsilon != 1.0
private const double DoubleEpsilon = 2.2204460492503131e-016;
+ private const float FloatEpsilon = 1.192092896e-07F;
+
///
/// AreClose - Returns whether or not two doubles are "close". That is, whether or
/// not they are within epsilon of each other.
@@ -26,6 +28,21 @@ namespace Avalonia.Utilities
return (-eps < delta) && (eps > delta);
}
+ ///
+ /// AreClose - Returns whether or not two floats are "close". That is, whether or
+ /// not they are within epsilon of each other.
+ ///
+ /// The first float to compare.
+ /// The second float to compare.
+ public static bool AreClose(float value1, float value2)
+ {
+ //in case they are Infinities (then epsilon check does not work)
+ if (value1 == value2) return true;
+ float eps = (Math.Abs(value1) + Math.Abs(value2) + 10.0f) * FloatEpsilon;
+ float delta = value1 - value2;
+ return (-eps < delta) && (eps > delta);
+ }
+
///
/// LessThan - Returns whether or not the first double is less than the second double.
/// That is, whether or not the first is strictly less than *and* not within epsilon of
@@ -38,6 +55,18 @@ namespace Avalonia.Utilities
return (value1 < value2) && !AreClose(value1, value2);
}
+ ///
+ /// LessThan - Returns whether or not the first float is less than the second float.
+ /// That is, whether or not the first is strictly less than *and* not within epsilon of
+ /// the other number.
+ ///
+ /// The first single float to compare.
+ /// The second single float to compare.
+ public static bool LessThan(float value1, float value2)
+ {
+ return (value1 < value2) && !AreClose(value1, value2);
+ }
+
///
/// GreaterThan - Returns whether or not the first double is greater than the second double.
/// That is, whether or not the first is strictly greater than *and* not within epsilon of
@@ -50,6 +79,18 @@ namespace Avalonia.Utilities
return (value1 > value2) && !AreClose(value1, value2);
}
+ ///
+ /// GreaterThan - Returns whether or not the first float is greater than the second float.
+ /// That is, whether or not the first is strictly greater than *and* not within epsilon of
+ /// the other number.
+ ///
+ /// The first float to compare.
+ /// The second float to compare.
+ public static bool GreaterThan(float value1, float value2)
+ {
+ return (value1 > value2) && !AreClose(value1, value2);
+ }
+
///
/// LessThanOrClose - Returns whether or not the first double is less than or close to
/// the second double. That is, whether or not the first is strictly less than or within
@@ -62,6 +103,18 @@ namespace Avalonia.Utilities
return (value1 < value2) || AreClose(value1, value2);
}
+ ///
+ /// LessThanOrClose - Returns whether or not the first float is less than or close to
+ /// the second float. That is, whether or not the first is strictly less than or within
+ /// epsilon of the other number.
+ ///
+ /// The first float to compare.
+ /// The second float to compare.
+ public static bool LessThanOrClose(float value1, float value2)
+ {
+ return (value1 < value2) || AreClose(value1, value2);
+ }
+
///
/// GreaterThanOrClose - Returns whether or not the first double is greater than or close to
/// the second double. That is, whether or not the first is strictly greater than or within
@@ -74,6 +127,18 @@ namespace Avalonia.Utilities
return (value1 > value2) || AreClose(value1, value2);
}
+ ///
+ /// GreaterThanOrClose - Returns whether or not the first float is greater than or close to
+ /// the second float. That is, whether or not the first is strictly greater than or within
+ /// epsilon of the other number.
+ ///
+ /// The first float to compare.
+ /// The second float to compare.
+ public static bool GreaterThanOrClose(float value1, float value2)
+ {
+ return (value1 > value2) || AreClose(value1, value2);
+ }
+
///
/// IsOne - Returns whether or not the double is "close" to 1. Same as AreClose(double, 1),
/// but this is faster.
@@ -84,6 +149,16 @@ namespace Avalonia.Utilities
return Math.Abs(value - 1.0) < 10.0 * DoubleEpsilon;
}
+ ///
+ /// IsOne - Returns whether or not the float is "close" to 1. Same as AreClose(float, 1),
+ /// but this is faster.
+ ///
+ /// The float to compare to 1.
+ public static bool IsOne(float value)
+ {
+ return Math.Abs(value - 1.0f) < 10.0f * FloatEpsilon;
+ }
+
///
/// IsZero - Returns whether or not the double is "close" to 0. Same as AreClose(double, 0),
/// but this is faster.
@@ -94,6 +169,16 @@ namespace Avalonia.Utilities
return Math.Abs(value) < 10.0 * DoubleEpsilon;
}
+ ///
+ /// IsZero - Returns whether or not the float is "close" to 0. Same as AreClose(float, 0),
+ /// but this is faster.
+ ///
+ /// The float to compare to 0.
+ public static bool IsZero(float value)
+ {
+ return Math.Abs(value) < 10.0f * FloatEpsilon;
+ }
+
///
/// Clamps a value between a minimum and maximum value.
///
From c4668f5ef3f57c639085a35b32e663ba78f5a440 Mon Sep 17 00:00:00 2001
From: Rustam Sayfutdinov
Date: Thu, 11 Jun 2020 23:43:52 +0300
Subject: [PATCH 3/3] Add tests for float math utils
---
.../Utilities/MathUtilitiesTests.cs | 85 ++++++++++++++-----
1 file changed, 62 insertions(+), 23 deletions(-)
diff --git a/tests/Avalonia.Base.UnitTests/Utilities/MathUtilitiesTests.cs b/tests/Avalonia.Base.UnitTests/Utilities/MathUtilitiesTests.cs
index a36b22fee2..0378a5b017 100644
--- a/tests/Avalonia.Base.UnitTests/Utilities/MathUtilitiesTests.cs
+++ b/tests/Avalonia.Base.UnitTests/Utilities/MathUtilitiesTests.cs
@@ -6,50 +6,89 @@ namespace Avalonia.Base.UnitTests.Utilities
{
public class MathUtilitiesTests
{
- [Fact]
- public void Two_Equivalent_Double_Values_Are_Close()
+ private const double AnyValue = 42.42;
+ private readonly double _calculatedAnyValue;
+ private readonly double _one;
+ private readonly double _zero;
+
+ public MathUtilitiesTests()
{
+ _calculatedAnyValue = 0.0;
+ _one = 0.0;
+ _zero = 1.0;
+
const int N = 10;
- var x = 42.42;
- var y = 0.0;
- var dx = x / N;
+ var dxAny = AnyValue / N;
+ var dxOne = 1.0 / N;
+ var dxZero = _zero / N;
for (var i = 0; i < N; ++i)
- y += dx;
- var actual = MathUtilities.AreClose(x, y);
+ {
+ _calculatedAnyValue += dxAny;
+ _one += dxOne;
+ _zero -= dxZero;
+ }
+ }
+
+ [Fact]
+ public void Two_Equivalent_Double_Values_Are_Close()
+ {
+ var actual = MathUtilities.AreClose(AnyValue, _calculatedAnyValue);
Assert.True(actual);
- Assert.Equal(x, Math.Round(y, 14));
+ Assert.Equal(AnyValue, Math.Round(_calculatedAnyValue, 14));
+ }
+
+ [Fact]
+ public void Two_Equivalent_Single_Values_Are_Close()
+ {
+ var expectedValue = (float)AnyValue;
+ var actualValue = (float)_calculatedAnyValue;
+
+ var actual = MathUtilities.AreClose(expectedValue, actualValue);
+
+ Assert.True(actual);
+ Assert.Equal((float) Math.Round(expectedValue, 5), (float) Math.Round(actualValue, 4));
}
[Fact]
public void Calculated_Double_One_Is_One()
{
- const int N = 10;
- var dx = 1.0 / N;
- var x = 0.0;
+ var actual = MathUtilities.IsOne(_one);
+
+ Assert.True(actual);
+ Assert.Equal(1.0, Math.Round(_one, 15));
+ }
+
+ [Fact]
+ public void Calculated_Single_One_Is_One()
+ {
+ var actualValue = (float)_one;
- for (var i = 0; i < N; ++i)
- x += dx;
- var actual = MathUtilities.IsOne(x);
+ var actual = MathUtilities.IsOne(actualValue);
Assert.True(actual);
- Assert.Equal(1.0, Math.Round(x, 15));
+ Assert.Equal(1.0f, (float) Math.Round(actualValue, 7));
}
[Fact]
public void Calculated_Double_Zero_Is_Zero()
{
- const int N = 10;
- var x = 1.0;
- var dx = x / N;
-
- for (var i = 0; i < N; ++i)
- x -= dx;
- var actual = MathUtilities.IsZero(x);
+ var actual = MathUtilities.IsZero(_zero);
+
+ Assert.True(actual);
+ Assert.Equal(0.0, Math.Round(_zero, 15));
+ }
+
+ [Fact]
+ public void Calculated_Single_Zero_Is_Zero()
+ {
+ var actualValue = (float)_zero;
+
+ var actual = MathUtilities.IsZero(actualValue);
Assert.True(actual);
- Assert.Equal(0.0, Math.Round(x, 15));
+ Assert.Equal(0.0f, (float) Math.Round(actualValue, 7));
}
[Fact]