From d7c82a1a6f7eb95b2214f20a281fa0581fb7b792 Mon Sep 17 00:00:00 2001
From: Tim <47110241+timunie@users.noreply.github.com>
Date: Tue, 5 Dec 2023 03:49:40 +0100
Subject: [PATCH] Fix: RangeBase should not write coerced values back when
DataContext is changing (#11918)
* Add failing test for RangeBase overriding Value on DataContext changed
* Add bool flag to skip coercing min, max and value while DataContext is
changing
---
src/Avalonia.Controls/Primitives/RangeBase.cs | 21 ++++++++++--
.../Primitives/RangeBaseTests.cs | 34 +++++++++++++++++++
2 files changed, 53 insertions(+), 2 deletions(-)
diff --git a/src/Avalonia.Controls/Primitives/RangeBase.cs b/src/Avalonia.Controls/Primitives/RangeBase.cs
index 33ab78b66f..b54dd314f9 100644
--- a/src/Avalonia.Controls/Primitives/RangeBase.cs
+++ b/src/Avalonia.Controls/Primitives/RangeBase.cs
@@ -10,6 +10,8 @@ namespace Avalonia.Controls.Primitives
///
public abstract class RangeBase : TemplatedControl
{
+ private bool _isDataContextChanging;
+
///
/// Defines the property.
///
@@ -74,7 +76,7 @@ namespace Avalonia.Controls.Primitives
private void OnMinimumChanged()
{
- if (IsInitialized)
+ if (IsInitialized && !_isDataContextChanging)
{
CoerceValue(MaximumProperty);
CoerceValue(ValueProperty);
@@ -99,8 +101,9 @@ namespace Avalonia.Controls.Primitives
private void OnMaximumChanged()
{
- if (IsInitialized)
+ if (IsInitialized && !_isDataContextChanging)
{
+ CoerceValue(MinimumProperty);
CoerceValue(ValueProperty);
}
}
@@ -170,6 +173,20 @@ namespace Avalonia.Controls.Primitives
RaiseEvent(valueChangedEventArgs);
}
}
+
+ ///
+ protected override void OnDataContextBeginUpdate()
+ {
+ _isDataContextChanging = true;
+ base.OnDataContextBeginUpdate();
+ }
+
+ ///
+ protected override void OnDataContextEndUpdate()
+ {
+ base.OnDataContextEndUpdate();
+ _isDataContextChanging = false;
+ }
///
/// Checks if the double value is not infinity nor NaN.
diff --git a/tests/Avalonia.Controls.UnitTests/Primitives/RangeBaseTests.cs b/tests/Avalonia.Controls.UnitTests/Primitives/RangeBaseTests.cs
index 67d22ea30e..e5d39212f7 100644
--- a/tests/Avalonia.Controls.UnitTests/Primitives/RangeBaseTests.cs
+++ b/tests/Avalonia.Controls.UnitTests/Primitives/RangeBaseTests.cs
@@ -1,5 +1,6 @@
using System;
using System.ComponentModel;
+using System.Security.Cryptography.X509Certificates;
using Avalonia.Controls.Primitives;
using Avalonia.Controls.Templates;
using Avalonia.Data;
@@ -27,6 +28,32 @@ namespace Avalonia.Controls.UnitTests.Primitives
Assert.Equal(100, target.Maximum);
}
+ [Fact]
+ public void ChangingDataContextShouldNotChangeOldDataContext()
+ {
+ var viewModel = new RangeTestViewModel()
+ {
+ Minimum = -5000,
+ Maximum = 5000,
+ Value = 4000
+ };
+
+ var target = new TestRange
+ {
+ [!RangeBase.MinimumProperty] = new Binding(nameof(viewModel.Minimum)),
+ [!RangeBase.MaximumProperty] = new Binding(nameof(viewModel.Maximum)),
+ [!RangeBase.ValueProperty] = new Binding(nameof(viewModel.Value)),
+ };
+
+ var root = new TestRoot(target);
+ target.DataContext = viewModel;
+ target.DataContext = null;
+
+ Assert.Equal(4000, viewModel.Value);
+ Assert.Equal(-5000, viewModel.Minimum);
+ Assert.Equal(5000, viewModel.Maximum);
+ }
+
[Fact]
public void Value_Should_Be_Coerced_To_Range()
{
@@ -217,5 +244,12 @@ namespace Avalonia.Controls.UnitTests.Primitives
}
}
}
+
+ private class RangeTestViewModel
+ {
+ public double Minimum { get; set; }
+ public double Maximum { get; set; }
+ public double Value { get; set; }
+ }
}
}