Browse Source

Merge branch 'fixes/8372-clear-local-value' into feature/7120-control-themes

Steven Kirk 3 years ago
parent
commit
ab3b0b31cd

+ 20 - 7
src/Avalonia.Base/Styling/PropertySetterInstance.cs

@@ -18,7 +18,7 @@ namespace Avalonia.Styling
         private readonly DirectPropertyBase<T>? _directProperty;
         private readonly T _value;
         private IDisposable? _subscription;
-        private bool _isActive;
+        private State _state;
 
         public PropertySetterInstance(
             IStyleable target,
@@ -40,6 +40,8 @@ namespace Avalonia.Styling
             _value = value;
         }
 
+        private bool IsActive => _state == State.Active;
+
         public void Start(bool hasActivator)
         {
             if (hasActivator)
@@ -70,31 +72,35 @@ namespace Avalonia.Styling
 
         public void Activate()
         {
-            if (!_isActive)
+            if (!IsActive)
             {
-                _isActive = true;
+                _state = State.Active;
                 PublishNext();
             }
         }
 
         public void Deactivate()
         {
-            if (_isActive)
+            if (IsActive)
             {
-                _isActive = false;
+                _state = State.Inactive;
                 PublishNext();
             }
         }
 
         public override void Dispose()
         {
+            if (_state == State.Disposed)
+                return;
+            _state = State.Disposed;
+
             if (_subscription is object)
             {
                 var sub = _subscription;
                 _subscription = null;
                 sub.Dispose();
             }
-            else if (_isActive)
+            else if (IsActive)
             {
                 if (_styledProperty is object)
                 {
@@ -114,7 +120,14 @@ namespace Avalonia.Styling
 
         private void PublishNext()
         {
-            PublishNext(_isActive ? new BindingValue<T>(_value) : default);
+            PublishNext(IsActive ? new BindingValue<T>(_value) : default);
+        }
+
+        private enum State
+        {
+            Inactive,
+            Active,
+            Disposed,
         }
     }
 }

+ 36 - 6
tests/Avalonia.Base.UnitTests/Styling/SetterTests.cs

@@ -150,13 +150,43 @@ namespace Avalonia.Base.UnitTests.Styling
             Assert.Equal(BindingPriority.StyleTrigger, control.GetDiagnostic(TextBlock.TagProperty).Priority);
         }
 
-        private IBinding CreateMockBinding(AvaloniaProperty property)
+        [Fact]
+        public void Disposing_Setter_Should_Preserve_LocalValue()
         {
-            var subject = new Subject<object>();
-            var descriptor = InstancedBinding.OneWay(subject);
-            var binding = Mock.Of<IBinding>(x => 
-                x.Initiate(It.IsAny<IAvaloniaObject>(), property, null, false) == descriptor);
-            return binding;
+            var control = new Canvas();
+            var setter = new Setter(TextBlock.TagProperty, "foo");
+
+            var instance = setter.Instance(control);
+            instance.Start(true);
+            instance.Activate();
+
+            control.Tag = "bar";
+
+            instance.Dispose();
+
+            Assert.Equal("bar", control.Tag);
+        }
+
+        [Fact]
+        public void Disposing_Binding_Setter_Should_Preserve_LocalValue()
+        {
+            var control = new Canvas();
+            var source = new { Foo = "foo" };
+            var setter = new Setter(TextBlock.TagProperty, new Binding
+            {
+                Source = source,
+                Path = nameof(source.Foo),
+            });
+
+            var instance = setter.Instance(control);
+            instance.Start(true);
+            instance.Activate();
+
+            control.Tag = "bar";
+
+            instance.Dispose();
+
+            Assert.Equal("bar", control.Tag);
         }
 
         private class TestConverter : IValueConverter