Browse Source

Slightly optimized ReevaluateEffectiveValue.

refactor/style-priorities
Steven Kirk 4 years ago
parent
commit
1e1d40134d
  1. 195
      src/Avalonia.Base/PropertyStore/ValueStore.cs

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

@ -644,37 +644,6 @@ namespace Avalonia.PropertyStore
return result;
}
private void ReevaluateEffectiveValue(
AvaloniaProperty property,
EffectiveValue? current,
bool ignoreLocalValue = false)
{
if (EvaluateEffectiveValue(
property,
!ignoreLocalValue ? current : null,
out var value,
out var priority,
out var baseValue,
out var basePriority))
{
if (current is null)
{
current = property.CreateEffectiveValue(Owner);
AddEffectiveValue(property, current);
}
if (basePriority != BindingPriority.Unset)
current.SetAndRaise(this, property, value, priority, baseValue, basePriority);
else
current.SetAndRaise(this, property, value, priority);
}
else if (current is not null)
{
RemoveEffectiveValue(property);
current.DisposeAndRaiseUnset(this, property);
}
}
private void AddEffectiveValue(AvaloniaProperty property, EffectiveValue effectiveValue)
{
_effectiveValues.Add(property, effectiveValue);
@ -740,102 +709,6 @@ namespace Avalonia.PropertyStore
return false;
}
/// <summary>
/// Evaluates the current value and base value for a property based on the current frames and optionally
/// local values. Does not evaluate inherited values.
/// </summary>
/// <param name="property">The property to evaluation</param>
/// <param name="current">The current effective value if the local value is to be considered.</param>
/// <param name="value">When the method exits will contain the current value if it exists.</param>
/// <param name="priority">When the method exits will contain the current value priority.</param>
/// <param name="baseValue">>When the method exits will contain the current base value if it exists.</param>
/// <param name="basePriority">When the method exits will contain the current base value priority.</param>
/// <returns>
/// True if a value was found, otherwise false.
/// </returns>
private bool EvaluateEffectiveValue(
AvaloniaProperty property,
EffectiveValue? current,
out object? value,
out BindingPriority priority,
out object? baseValue,
out BindingPriority basePriority)
{
var i = _frames.Count - 1;
value = baseValue = AvaloniaProperty.UnsetValue;
priority = basePriority = BindingPriority.Unset;
// First try to find an animation value.
for (; i >= 0; --i)
{
var frame = _frames[i];
if (frame.Priority > BindingPriority.Animation)
break;
if (frame.IsActive &&
frame.TryGetEntry(property, out var entry) &&
entry.TryGetValue(out value))
{
priority = frame.Priority;
--i;
break;
}
}
// Local values come from the current EffectiveValue.
if (current?.Priority == BindingPriority.LocalValue)
{
// If there's a current effective local value and no animated value then we use the
// effective local value.
if (priority == BindingPriority.Unset)
{
value = current.Value;
priority = BindingPriority.LocalValue;
}
// The local value is always the base value.
baseValue = current.Value;
basePriority = BindingPriority.LocalValue;
return true;
}
// Or the current effective base value if there's no longer an animated value.
if (priority == BindingPriority.Unset && current?.BasePriority == BindingPriority.LocalValue)
{
value = baseValue = current.BaseValue;
priority = basePriority = BindingPriority.LocalValue;
return true;
}
// Now try the rest of the frames.
for (; i >= 0; --i)
{
var frame = _frames[i];
if (frame.Priority <= BindingPriority.LocalValue)
continue;
if (frame.IsActive &&
frame.TryGetEntry(property, out var entry) &&
entry.TryGetValue(out var v))
{
if (priority == BindingPriority.Unset)
{
value = v;
priority = frame.Priority;
}
baseValue = v;
basePriority = frame.Priority;
return true;
}
}
return priority != BindingPriority.Unset;
}
private void InheritedValueChanged(
AvaloniaProperty property,
EffectiveValue? oldValue,
@ -866,6 +739,74 @@ namespace Avalonia.PropertyStore
}
}
private void ReevaluateEffectiveValue(
AvaloniaProperty property,
EffectiveValue? current,
bool ignoreLocalValue = false)
{
restart:
// Don't reevaluate if a styling pass is in effect, reevaluation will be done when
// it has finished.
if (_styling > 0)
return;
var generation = _frameGeneration;
// Reset all non-LocalValue effective value to Unset priority.
if (current is not null)
{
if (ignoreLocalValue || current.Priority != BindingPriority.LocalValue)
current.SetPriority(BindingPriority.Unset);
if (ignoreLocalValue || current.BasePriority != BindingPriority.LocalValue)
current.SetBasePriority(BindingPriority.Unset);
}
// Iterate the frames to get the effective value.
for (var i = _frames.Count - 1; i >= 0; --i)
{
var frame = _frames[i];
if (!frame.IsActive)
continue;
var priority = frame.Priority;
if (frame.TryGetEntry(property, out var entry) && entry.HasValue)
{
if (current is not null)
{
current.SetAndRaise(this, entry, priority);
}
else
{
current = property.CreateEffectiveValue(Owner);
AddEffectiveValue(property, current);
current.SetAndRaise(this, entry, priority);
}
}
if (current is not null &&
current.Priority < BindingPriority.Unset &&
current.BasePriority < BindingPriority.Unset)
return;
if (generation != _frameGeneration)
goto restart;
}
if (current?.Priority == BindingPriority.Unset)
{
if (current.BasePriority == BindingPriority.Unset)
{
RemoveEffectiveValue(property);
current.DisposeAndRaiseUnset(this, property);
}
else
{
current.SetAndRaise(this, property, current.BaseValue, current.BasePriority);
}
}
}
private void ReevaluateEffectiveValues()
{
restart:

Loading…
Cancel
Save