From 4340052cae4e98fe05ff514f357bbab4777ff65a Mon Sep 17 00:00:00 2001 From: Tim Date: Fri, 12 May 2023 14:12:40 +0200 Subject: [PATCH 1/4] fix incement / decrement when value was null --- src/Avalonia.Controls/NumericUpDown/NumericUpDown.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Avalonia.Controls/NumericUpDown/NumericUpDown.cs b/src/Avalonia.Controls/NumericUpDown/NumericUpDown.cs index 885a8af5d1..e97692b255 100644 --- a/src/Avalonia.Controls/NumericUpDown/NumericUpDown.cs +++ b/src/Avalonia.Controls/NumericUpDown/NumericUpDown.cs @@ -659,7 +659,9 @@ namespace Avalonia.Controls } else { - result = Minimum; + // if Minimum is set (i.e: Minimum is greater than decimal.MinValue) we set value to Minimum on Increment. + // otherwise we set value to 0. It ill be clamped to be between Minimum and Maximum later, so we don't need to do it here. + result = Minimum > decimal.MinValue ? Minimum : 0; } SetCurrentValue(ValueProperty, MathUtilities.Clamp(result, Minimum, Maximum)); @@ -678,7 +680,9 @@ namespace Avalonia.Controls } else { - result = Maximum; + // if Maximum is set (i.e: Maximum is smaller than decimal.MaxValue) we set value to Maximum on decrement. + // otherwise we set value to 0. It ill be clamped to be between Minimum and Maximum later, so we don't need to do it here. + result = Maximum < decimal.MaxValue ? Maximum : 0; } SetCurrentValue(ValueProperty, MathUtilities.Clamp(result, Minimum, Maximum)); From d5b73e21095b6b21621b47364e82c9f3ce577c09 Mon Sep 17 00:00:00 2001 From: Tim Date: Fri, 12 May 2023 15:00:19 +0200 Subject: [PATCH 2/4] Add some unit tests for Incement / Decrement --- .../NumericUpDownTests.cs | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/tests/Avalonia.Controls.UnitTests/NumericUpDownTests.cs b/tests/Avalonia.Controls.UnitTests/NumericUpDownTests.cs index d8738bf44b..8e62918049 100644 --- a/tests/Avalonia.Controls.UnitTests/NumericUpDownTests.cs +++ b/tests/Avalonia.Controls.UnitTests/NumericUpDownTests.cs @@ -1,8 +1,10 @@ using System; +using System.Collections.Generic; using System.Linq; using System.Reactive.Subjects; using Avalonia.Controls.Templates; using Avalonia.Data; +using Avalonia.Interactivity; using Avalonia.Threading; using Avalonia.UnitTests; using Xunit; @@ -43,6 +45,38 @@ namespace Avalonia.Controls.UnitTests }); } + [Theory] + [MemberData(nameof(Increment_Decrement_TestData))] + public void Increment_Decrement_Tests(decimal min, decimal max, decimal? value, SpinDirection direction, + decimal? expected) + { + var control = CreateControl(); + control.Minimum = min; + control.Maximum = max; + control.Value = value; + + var spinner = GetSpinner(control); + + spinner.RaiseEvent(new SpinEventArgs(Spinner.SpinEvent, direction)); + + Assert.Equal(control.Value, expected); + } + + public static IEnumerable Increment_Decrement_TestData() + { + // if min and max are not defined and value was null, 0 should be ne new value after spin + yield return new object[] { decimal.MinValue, decimal.MaxValue, null, SpinDirection.Decrease, 0m }; + yield return new object[] { decimal.MinValue, decimal.MaxValue, null, SpinDirection.Increase, 0m }; + + // if no value was defined, but Min or Max are defined, use these as the new value + yield return new object[] { -400m, -200m, null, SpinDirection.Decrease, -200m }; + yield return new object[] { 200m, 400m, null, SpinDirection.Increase, 200m }; + + // Value should be clamped to Min / Max after spinning + yield return new object[] { 200m, 400m, 5m, SpinDirection.Increase, 200m }; + yield return new object[] { 200m, 400m, 200m, SpinDirection.Decrease, 200m }; + } + private void RunTest(Action test) { using (UnitTestApplication.Start(Services)) @@ -76,6 +110,14 @@ namespace Avalonia.Controls.UnitTests .OfType() .First(); } + + private static ButtonSpinner GetSpinner(NumericUpDown control) + { + return control.GetTemplateChildren() + .OfType() + .First(); + } + private static IControlTemplate CreateTemplate() { return new FuncControlTemplate((control, scope) => From a2cf40c812b3f52796890047d33dec1e22a38988 Mon Sep 17 00:00:00 2001 From: Tim Date: Fri, 12 May 2023 15:08:33 +0200 Subject: [PATCH 3/4] Use `IsSet` instead of hardcoded values --- src/Avalonia.Controls/NumericUpDown/NumericUpDown.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Avalonia.Controls/NumericUpDown/NumericUpDown.cs b/src/Avalonia.Controls/NumericUpDown/NumericUpDown.cs index e97692b255..b5be12fa54 100644 --- a/src/Avalonia.Controls/NumericUpDown/NumericUpDown.cs +++ b/src/Avalonia.Controls/NumericUpDown/NumericUpDown.cs @@ -659,9 +659,9 @@ namespace Avalonia.Controls } else { - // if Minimum is set (i.e: Minimum is greater than decimal.MinValue) we set value to Minimum on Increment. + // if Minimum is set we set value to Minimum on Increment. // otherwise we set value to 0. It ill be clamped to be between Minimum and Maximum later, so we don't need to do it here. - result = Minimum > decimal.MinValue ? Minimum : 0; + result = IsSet(MinimumProperty) ? Minimum : 0; } SetCurrentValue(ValueProperty, MathUtilities.Clamp(result, Minimum, Maximum)); @@ -680,9 +680,9 @@ namespace Avalonia.Controls } else { - // if Maximum is set (i.e: Maximum is smaller than decimal.MaxValue) we set value to Maximum on decrement. + // if Maximum is set we set value to Maximum on decrement. // otherwise we set value to 0. It ill be clamped to be between Minimum and Maximum later, so we don't need to do it here. - result = Maximum < decimal.MaxValue ? Maximum : 0; + result = IsSet(MaximumProperty) ? Maximum : 0; } SetCurrentValue(ValueProperty, MathUtilities.Clamp(result, Minimum, Maximum)); From 85b816c27f723bbbc825062afda9966092844737 Mon Sep 17 00:00:00 2001 From: Tim Date: Fri, 12 May 2023 15:17:05 +0200 Subject: [PATCH 4/4] fix unit tests Do not set Min / max in case it is decimal,Min / decimal.Max --- tests/Avalonia.Controls.UnitTests/NumericUpDownTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Avalonia.Controls.UnitTests/NumericUpDownTests.cs b/tests/Avalonia.Controls.UnitTests/NumericUpDownTests.cs index 8e62918049..24f246d188 100644 --- a/tests/Avalonia.Controls.UnitTests/NumericUpDownTests.cs +++ b/tests/Avalonia.Controls.UnitTests/NumericUpDownTests.cs @@ -51,8 +51,8 @@ namespace Avalonia.Controls.UnitTests decimal? expected) { var control = CreateControl(); - control.Minimum = min; - control.Maximum = max; + if (min > decimal.MinValue) control.Minimum = min; + if (max < decimal.MaxValue) control.Maximum = max; control.Value = value; var spinner = GetSpinner(control);