Browse Source

Merge pull request #2683 from AvaloniaUI/fixes/2372-slider-coercion

Don't coerce RangeBase values until initialized.
no-llvmpipe
Nikita Tsukanov 7 years ago
committed by GitHub
parent
commit
a6f8e523bf
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 65
      src/Avalonia.Controls/Primitives/RangeBase.cs
  2. 10
      src/Avalonia.Styling/StyledElement.cs
  3. 39
      tests/Avalonia.Controls.UnitTests/Primitives/RangeBaseTests.cs
  4. 19
      tests/Avalonia.Markup.Xaml.UnitTests/Xaml/BasicTests.cs

65
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);
}
/// <summary>
/// Throws an exception if the double value is NaN or Inf.
/// </summary>
@ -142,17 +176,6 @@ namespace Avalonia.Controls.Primitives
}
}
/// <summary>
/// Validates the <see cref="Minimum"/> property.
/// </summary>
/// <param name="value">The value.</param>
/// <returns>The coerced value.</returns>
private double ValidateMinimum(double value)
{
ValidateDouble(value, "Minimum");
return value;
}
/// <summary>
/// Validates/coerces the <see cref="Maximum"/> property.
/// </summary>
@ -160,7 +183,6 @@ namespace Avalonia.Controls.Primitives
/// <returns>The coerced value.</returns>
private double ValidateMaximum(double value)
{
ValidateDouble(value, "Maximum");
return Math.Max(value, Minimum);
}
@ -171,7 +193,6 @@ namespace Avalonia.Controls.Primitives
/// <returns>The coerced value.</returns>
private double ValidateValue(double value)
{
ValidateDouble(value, "Value");
return MathUtilities.Clamp(value, Minimum, Maximum);
}
}

10
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()
{
}
/// <summary>
/// Called when the control finishes initialization.
/// </summary>
protected virtual void OnInitialized()
{
}
private static void DataContextNotifying(IAvaloniaObject o, bool updateStarted)
{
if (o is StyledElement element)

39
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
}
}
}
}
}

19
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 = @"
<Window xmlns='https://github.com/avaloniaui'>
<Slider Width='400' Value='500' Minimum='0' Maximum='1000'/>
</Window>";
var window = AvaloniaXamlLoader.Parse<Window>(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; }

Loading…
Cancel
Save