Browse Source

Prevent re-entrancy in PropertySetterInstance.Dispose.

The call to `_subscription.Dispose()` causes `BindingEntry.Dispose()` to call `_subscription.Dispose()`, but in this case the `BindingEntry._subscription` instance is the `PropertySetterInstance`!

Except now `PropertySetterInstance._subscription` is null, and so `PropertySetterInstance.Dispose` called `ClearValue`, which is obviously wrong.
pull/8373/head
Steven Kirk 4 years ago
parent
commit
857bfb5bd2
  1. 27
      src/Avalonia.Base/Styling/PropertySetterInstance.cs

27
src/Avalonia.Base/Styling/PropertySetterInstance.cs

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

Loading…
Cancel
Save