Преглед изворни кода

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
Tim пре 1 година
родитељ
комит
d7c82a1a6f

+ 19 - 2
src/Avalonia.Controls/Primitives/RangeBase.cs

@@ -10,6 +10,8 @@ namespace Avalonia.Controls.Primitives
     /// </summary>
     public abstract class RangeBase : TemplatedControl
     {
+        private bool _isDataContextChanging;
+        
         /// <summary>
         /// Defines the <see cref="Minimum"/> property.
         /// </summary>
@@ -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);
             }
         }
+        
+        /// <inheritdoc />
+        protected override void OnDataContextBeginUpdate()
+        {
+            _isDataContextChanging = true;
+            base.OnDataContextBeginUpdate();
+        }
+
+        /// <inheritdoc />
+        protected override void OnDataContextEndUpdate()
+        {
+            base.OnDataContextEndUpdate();
+            _isDataContextChanging = false;
+        }
 
         /// <summary>
         /// Checks if the double value is not infinity nor NaN.

+ 34 - 0
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; }
+        }
     }
 }