Skip to content

Commit

Permalink
Merge pull request AvaloniaUI#8373 from AvaloniaUI/fixes/8372-clear-l…
Browse files Browse the repository at this point in the history
…ocal-value

Correctly clear PriorityValue local value
  • Loading branch information
maxkatz6 authored and danwalmsley committed Jul 6, 2022
1 parent 9d05161 commit 751fd6e
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 13 deletions.
1 change: 1 addition & 0 deletions src/Avalonia.Base/PropertyStore/PriorityValue.cs
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ public void EndBatchUpdate()

public void ClearLocalValue()
{
_localValue = default;
UpdateEffectiveValue(new AvaloniaPropertyChangedEventArgs<T>(
_owner,
Property,
Expand Down
27 changes: 20 additions & 7 deletions src/Avalonia.Styling/Styling/PropertySetterInstance.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ internal class PropertySetterInstance<T> : SingleSubscriberObservableBase<Bindin
private readonly DirectPropertyBase<T>? _directProperty;
private readonly T _value;
private IDisposable? _subscription;
private bool _isActive;
private State _state;

public PropertySetterInstance(
IStyleable target,
Expand All @@ -40,6 +40,8 @@ public PropertySetterInstance(
_value = value;
}

private bool IsActive => _state == State.Active;

public void Start(bool hasActivator)
{
if (hasActivator)
Expand Down Expand Up @@ -68,31 +70,35 @@ public void Start(bool hasActivator)

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)
{
Expand All @@ -112,7 +118,14 @@ protected override void Unsubscribed() { }

private void PublishNext()
{
PublishNext(_isActive ? new BindingValue<T>(_value) : default);
PublishNext(IsActive ? new BindingValue<T>(_value) : default);
}

private enum State
{
Inactive,
Active,
Disposed,
}
}
}
15 changes: 15 additions & 0 deletions tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_SetValue.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,21 @@ public void ClearValue_Clears_Value()
Assert.Equal("foodefault", target.GetValue(Class1.FooProperty));
}

[Fact]
public void ClearValue_Resets_Value_To_Style_value()
{
Class1 target = new Class1();

target.SetValue(Class1.FooProperty, "style", BindingPriority.Style);
target.SetValue(Class1.FooProperty, "local");

Assert.Equal("local", target.GetValue(Class1.FooProperty));

target.ClearValue(Class1.FooProperty);

Assert.Equal("style", target.GetValue(Class1.FooProperty));
}

[Fact]
public void ClearValue_Raises_PropertyChanged()
{
Expand Down
42 changes: 36 additions & 6 deletions tests/Avalonia.Styling.UnitTests/SetterTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -151,13 +151,43 @@ public void Setter_Should_Apply_Binding_With_Activator_With_StyleTrigger_Priorit
BindingPriority.StyleTrigger));
}

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
Expand Down

0 comments on commit 751fd6e

Please sign in to comment.