diff --git a/src/Avalonia.Controls/Primitives/RangeBase.cs b/src/Avalonia.Controls/Primitives/RangeBase.cs index ae175734b9..f1ee7c0e1a 100644 --- a/src/Avalonia.Controls/Primitives/RangeBase.cs +++ b/src/Avalonia.Controls/Primitives/RangeBase.cs @@ -75,10 +75,18 @@ namespace Avalonia.Controls.Primitives set { - value = ValidateMinimum(value); - SetAndRaise(MinimumProperty, ref _minimum, value); - Maximum = ValidateMaximum(Maximum); - Value = ValidateValue(Value); + ValidateDouble(value, "Minimum"); + + if (IsInitialized) + { + SetAndRaise(MinimumProperty, ref _minimum, value); + Maximum = ValidateMaximum(Maximum); + Value = ValidateValue(Value); + } + else + { + SetAndRaise(MinimumProperty, ref _minimum, value); + } } } @@ -94,9 +102,18 @@ namespace Avalonia.Controls.Primitives set { - value = ValidateMaximum(value); - SetAndRaise(MaximumProperty, ref _maximum, value); - Value = ValidateValue(Value); + ValidateDouble(value, "Maximum"); + + if (IsInitialized) + { + value = ValidateMaximum(value); + SetAndRaise(MaximumProperty, ref _maximum, value); + Value = ValidateValue(Value); + } + else + { + SetAndRaise(MaximumProperty, ref _maximum, value); + } } } @@ -112,8 +129,17 @@ namespace Avalonia.Controls.Primitives set { - value = ValidateValue(value); - SetAndRaise(ValueProperty, ref _value, value); + ValidateDouble(value, "Value"); + + if (IsInitialized) + { + value = ValidateValue(value); + SetAndRaise(ValueProperty, ref _value, value); + } + else + { + SetAndRaise(ValueProperty, ref _value, value); + } } } @@ -129,6 +155,14 @@ namespace Avalonia.Controls.Primitives set => SetValue(LargeChangeProperty, value); } + protected override void OnInitialized() + { + base.OnInitialized(); + + Maximum = ValidateMaximum(Maximum); + Value = ValidateValue(Value); + } + /// /// Throws an exception if the double value is NaN or Inf. /// @@ -142,17 +176,6 @@ namespace Avalonia.Controls.Primitives } } - /// - /// Validates the property. - /// - /// The value. - /// The coerced value. - private double ValidateMinimum(double value) - { - ValidateDouble(value, "Minimum"); - return value; - } - /// /// Validates/coerces the property. /// @@ -160,7 +183,6 @@ namespace Avalonia.Controls.Primitives /// The coerced value. private double ValidateMaximum(double value) { - ValidateDouble(value, "Maximum"); return Math.Max(value, Minimum); } @@ -171,7 +193,6 @@ namespace Avalonia.Controls.Primitives /// The coerced value. private double ValidateValue(double value) { - ValidateDouble(value, "Value"); return MathUtilities.Clamp(value, Minimum, Maximum); } } diff --git a/src/Avalonia.Styling/StyledElement.cs b/src/Avalonia.Styling/StyledElement.cs index f7e063dfb5..146a4c75e7 100644 --- a/src/Avalonia.Styling/StyledElement.cs +++ b/src/Avalonia.Styling/StyledElement.cs @@ -392,6 +392,7 @@ namespace Avalonia if (_initCount == 0 && !IsInitialized) { IsInitialized = true; + OnInitialized(); Initialized?.Invoke(this, EventArgs.Empty); } } @@ -608,7 +609,14 @@ namespace Avalonia protected virtual void OnDataContextEndUpdate() { } - + + /// + /// Called when the control finishes initialization. + /// + protected virtual void OnInitialized() + { + } + private static void DataContextNotifying(IAvaloniaObject o, bool updateStarted) { if (o is StyledElement element) diff --git a/tests/Avalonia.Controls.UnitTests/Primitives/RangeBaseTests.cs b/tests/Avalonia.Controls.UnitTests/Primitives/RangeBaseTests.cs index 42578c61ac..d913e3e54f 100644 --- a/tests/Avalonia.Controls.UnitTests/Primitives/RangeBaseTests.cs +++ b/tests/Avalonia.Controls.UnitTests/Primitives/RangeBaseTests.cs @@ -8,6 +8,7 @@ using Avalonia.Controls.Templates; using Avalonia.Data; using Avalonia.Markup.Data; using Avalonia.Styling; +using Avalonia.UnitTests; using Xunit; namespace Avalonia.Controls.UnitTests.Primitives @@ -22,6 +23,7 @@ namespace Avalonia.Controls.UnitTests.Primitives Minimum = 100, Maximum = 50, }; + var root = new TestRoot(target); Assert.Equal(100, target.Minimum); Assert.Equal(100, target.Maximum); @@ -36,6 +38,7 @@ namespace Avalonia.Controls.UnitTests.Primitives Maximum = 50, Value = 100, }; + var root = new TestRoot(target); Assert.Equal(0, target.Minimum); Assert.Equal(50, target.Maximum); @@ -51,6 +54,7 @@ namespace Avalonia.Controls.UnitTests.Primitives Maximum = 100, Value = 50, }; + var root = new TestRoot(target); target.Minimum = 200; @@ -68,6 +72,7 @@ namespace Avalonia.Controls.UnitTests.Primitives Maximum = 100, Value = 100, }; + var root = new TestRoot(target); target.Maximum = 50; @@ -160,6 +165,38 @@ namespace Avalonia.Controls.UnitTests.Primitives Assert.Equal(expected, track.Value); } + [Fact] + public void Coercion_Should_Not_Be_Done_During_Initialization() + { + var target = new TestRange(); + + target.BeginInit(); + + var root = new TestRoot(target); + target.Minimum = 1; + Assert.Equal(0, target.Value); + + target.Value = 50; + target.EndInit(); + + Assert.Equal(50, target.Value); + } + + [Fact] + public void Coercion_Should_Be_Done_After_Initialization() + { + var target = new TestRange(); + + target.BeginInit(); + + var root = new TestRoot(target); + target.Minimum = 1; + + target.EndInit(); + + Assert.Equal(1, target.Value); + } + private class TestRange : RangeBase { } @@ -199,4 +236,4 @@ namespace Avalonia.Controls.UnitTests.Primitives } } } -} \ No newline at end of file +} diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/BasicTests.cs b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/BasicTests.cs index 7fe0fc4a08..720ff3b0de 100644 --- a/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/BasicTests.cs +++ b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/BasicTests.cs @@ -907,6 +907,25 @@ do we need it?")] } } + [Fact] + public void Slider_Properties_Can_Be_Set_In_Any_Order() + { + using (UnitTestApplication.Start(TestServices.MockWindowingPlatform)) + { + var xaml = @" + + +"; + + var window = AvaloniaXamlLoader.Parse(xaml); + var slider = (Slider)window.Content; + + Assert.Equal(0, slider.Minimum); + Assert.Equal(1000, slider.Maximum); + Assert.Equal(500, slider.Value); + } + } + private class SelectedItemsViewModel : INotifyPropertyChanged { public string[] Items { get; set; }