diff --git a/src/Avalonia.Controls/NumericUpDown/NumericUpDown.cs b/src/Avalonia.Controls/NumericUpDown/NumericUpDown.cs index 885a8af5d1..b5be12fa54 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 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 = IsSet(MinimumProperty) ? Minimum : 0; } SetCurrentValue(ValueProperty, MathUtilities.Clamp(result, Minimum, Maximum)); @@ -678,7 +680,9 @@ namespace Avalonia.Controls } else { - result = Maximum; + // 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 = IsSet(MaximumProperty) ? Maximum : 0; } SetCurrentValue(ValueProperty, MathUtilities.Clamp(result, Minimum, Maximum)); diff --git a/tests/Avalonia.Controls.UnitTests/NumericUpDownTests.cs b/tests/Avalonia.Controls.UnitTests/NumericUpDownTests.cs index d8738bf44b..24f246d188 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(); + if (min > decimal.MinValue) control.Minimum = min; + if (max < decimal.MaxValue) 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) =>