Browse Source

Re-evaluate all properties if necessary.

When re-evaluating a single property, if the frame activation state changes then we need to re-evaluate all properties.
pull/8600/head
Steven Kirk 4 years ago
parent
commit
12f72ddd61
  1. 8
      src/Avalonia.Base/PropertyStore/ImmediateValueFrame.cs
  2. 15
      src/Avalonia.Base/PropertyStore/ValueFrame.cs
  3. 36
      src/Avalonia.Base/PropertyStore/ValueStore.cs
  4. 32
      src/Avalonia.Base/Styling/StyleInstance.cs

8
src/Avalonia.Base/PropertyStore/ImmediateValueFrame.cs

@ -14,8 +14,6 @@ namespace Avalonia.PropertyStore
Priority = priority;
}
public override bool IsActive => true;
public TypedBindingEntry<T> AddBinding<T>(
StyledPropertyBase<T> property,
IObservable<BindingValue<T>> source)
@ -55,5 +53,11 @@ namespace Avalonia.PropertyStore
Remove(value.Property);
Owner?.OnValueEntryRemoved(this, value.Property);
}
protected override bool GetIsActive(out bool hasChanged)
{
hasChanged = false;
return true;
}
}
}

15
src/Avalonia.Base/PropertyStore/ValueFrame.cs

@ -15,7 +15,7 @@ namespace Avalonia.PropertyStore
private bool _isShared;
public int EntryCount => _entries.Count;
public abstract bool IsActive { get; }
public bool IsActive => GetIsActive(out _);
public ValueStore? Owner => !_isShared ? _owner :
throw new AvaloniaInternalException("Cannot get owner for shared ValueFrame");
public BindingPriority Priority { get; protected set; }
@ -32,9 +32,16 @@ namespace Avalonia.PropertyStore
_owner = owner;
}
public bool TryGetEntry(AvaloniaProperty property, [NotNullWhen(true)] out IValueEntry? entry)
public bool TryGetEntryIfActive(
AvaloniaProperty property,
[NotNullWhen(true)] out IValueEntry? entry,
out bool activeChanged)
{
return _index.TryGetValue(property, out entry);
if (_index.TryGetValue(property, out entry) &&
GetIsActive(out activeChanged))
return true;
activeChanged = false;
return false;
}
public void OnBindingCompleted(IValueEntry binding)
@ -49,6 +56,8 @@ namespace Avalonia.PropertyStore
_entries[i].Unsubscribe();
}
protected abstract bool GetIsActive(out bool hasChanged);
protected void MakeShared()
{
_isShared = true;

36
src/Avalonia.Base/PropertyStore/ValueStore.cs

@ -788,19 +788,29 @@ namespace Avalonia.PropertyStore
var frame = _frames[i];
var priority = frame.Priority;
if (frame.TryGetEntry(property, out var entry) &&
frame.IsActive &&
entry.HasValue)
if (frame.TryGetEntryIfActive(property, out var entry, out var activeChanged))
{
if (current is not null)
// If The active state of the frame has changed since the last read, and
// the frame holds multiple values then we need to re-evaluate the
// effective values of all properties.
if (activeChanged && frame.EntryCount > 1)
{
current.SetAndRaise(this, entry, priority);
ReevaluateEffectiveValues();
return;
}
else
if (entry.HasValue)
{
current = property.CreateEffectiveValue(Owner);
AddEffectiveValue(property, current);
current.SetAndRaise(this, entry, priority);
if (current is not null)
{
current.SetAndRaise(this, entry, priority);
}
else
{
current = property.CreateEffectiveValue(Owner);
AddEffectiveValue(property, current);
current.SetAndRaise(this, entry, priority);
}
}
}
@ -879,10 +889,13 @@ namespace Avalonia.PropertyStore
var property = entry.Property;
EffectiveValue? effectiveValue;
// Skip if we already have a value/base value for this property.
// Unsubscribe and skip if we already have a value/base value for this property.
if (_effectiveValues.TryGetValue(property, out effectiveValue) == true &&
effectiveValue.BasePriority < BindingPriority.Unset)
{
entry.Unsubscribe();
continue;
}
if (!entry.HasValue)
continue;
@ -950,8 +963,7 @@ namespace Avalonia.PropertyStore
}
if ((foundBaseValue || frame.Priority <= BindingPriority.Animation) &&
frame.TryGetEntry(property, out var entry) &&
frame.IsActive)
frame.TryGetEntryIfActive(property, out var entry, out _))
{
entry.Unsubscribe();
}

32
src/Avalonia.Base/Styling/StyleInstance.cs

@ -22,6 +22,7 @@ namespace Avalonia.Styling
internal class StyleInstance : ValueFrame, IStyleInstance, IStyleActivatorSink, IDisposable
{
private readonly IStyleActivator? _activator;
private bool _isActive;
private List<ISetterInstance>? _setters;
private List<IAnimation>? _animations;
private Subject<bool>? _animationTrigger;
@ -35,22 +36,10 @@ namespace Avalonia.Styling
public bool HasActivator => _activator is object;
public override bool IsActive
{
get
{
if (_activator?.IsSubscribed == false)
{
_activator.Subscribe(this);
_animationTrigger?.OnNext(_activator.IsActive);
}
return _activator?.IsActive ?? true;
}
}
public IStyle Source { get; }
bool IStyleInstance.IsActive => _isActive;
public void Add(ISetterInstance instance)
{
if (instance is IValueEntry valueEntry)
@ -95,5 +84,20 @@ namespace Avalonia.Styling
Owner?.OnFrameActivationChanged(this);
_animationTrigger?.OnNext(value);
}
protected override bool GetIsActive(out bool hasChanged)
{
var previous = _isActive;
if (_activator?.IsSubscribed == false)
{
_activator.Subscribe(this);
_animationTrigger?.OnNext(_activator.IsActive);
}
_isActive = _activator?.IsActive ?? true;
hasChanged = _isActive != previous;
return _isActive;
}
}
}

Loading…
Cancel
Save