|
|
|
@ -395,7 +395,7 @@ namespace Avalonia.PropertyStore |
|
|
|
if (TryGetEffectiveValue(property, out var existing)) |
|
|
|
{ |
|
|
|
if (priority <= existing.BasePriority) |
|
|
|
ReevaluateEffectiveValue(property, existing); |
|
|
|
ReevaluateEffectiveValue(property, existing, changedValueEntry: entry); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
@ -774,6 +774,7 @@ namespace Avalonia.PropertyStore |
|
|
|
private void ReevaluateEffectiveValue( |
|
|
|
AvaloniaProperty property, |
|
|
|
EffectiveValue? current, |
|
|
|
IValueEntry? changedValueEntry = null, |
|
|
|
bool ignoreLocalValue = false) |
|
|
|
{ |
|
|
|
++_isEvaluating; |
|
|
|
@ -796,6 +797,12 @@ namespace Avalonia.PropertyStore |
|
|
|
{ |
|
|
|
var frame = _frames[i]; |
|
|
|
var priority = frame.Priority; |
|
|
|
|
|
|
|
// Exit early if the current EffectiveValue has higher priority than this frame.
|
|
|
|
if (current?.Priority < priority && current?.BasePriority < priority) |
|
|
|
break; |
|
|
|
|
|
|
|
// Try to get an entry from the frame for the property we're reevaluating.
|
|
|
|
var foundEntry = frame.TryGetEntryIfActive(property, out var entry, out var activeChanged); |
|
|
|
|
|
|
|
// If the active state of the frame has changed since the last read, and
|
|
|
|
@ -803,20 +810,17 @@ namespace Avalonia.PropertyStore |
|
|
|
// effective values of all properties.
|
|
|
|
if (activeChanged && frame.EntryCount > 1) |
|
|
|
{ |
|
|
|
ReevaluateEffectiveValues(); |
|
|
|
ReevaluateEffectiveValues(changedValueEntry); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
// We're interested in the value if:
|
|
|
|
// - There is no current effective value, or
|
|
|
|
// - The value's priority is higher than the current effective value's priority, or
|
|
|
|
// - The value is a non-animation value and its priority is higher than the current
|
|
|
|
// effective value's base priority
|
|
|
|
var isRelevantPriority = current is null || |
|
|
|
(priority < current.Priority && priority < current.BasePriority) || |
|
|
|
(priority > BindingPriority.Animation && priority < current.BasePriority); |
|
|
|
|
|
|
|
if (foundEntry && isRelevantPriority && entry!.HasValue) |
|
|
|
// If the frame has an entry for this property with a higher priority than the
|
|
|
|
// current effective value (and that entry has a value), then we have a new
|
|
|
|
// value for the property. Note that the check for entry.HasValue must be
|
|
|
|
// evaluated last as it can cause bindings to be subscribed.
|
|
|
|
if (foundEntry && |
|
|
|
HasHigherPriority(entry!, priority, current, changedValueEntry) && |
|
|
|
entry!.HasValue) |
|
|
|
{ |
|
|
|
if (current is not null) |
|
|
|
{ |
|
|
|
@ -832,10 +836,6 @@ namespace Avalonia.PropertyStore |
|
|
|
|
|
|
|
if (generation != _frameGeneration) |
|
|
|
goto restart; |
|
|
|
|
|
|
|
if (current?.Priority < BindingPriority.Unset && |
|
|
|
current?.BasePriority < BindingPriority.Unset) |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
|
if (current?.Priority == BindingPriority.Unset) |
|
|
|
@ -859,7 +859,7 @@ namespace Avalonia.PropertyStore |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
private void ReevaluateEffectiveValues() |
|
|
|
private void ReevaluateEffectiveValues(IValueEntry? changedValueEntry = null) |
|
|
|
{ |
|
|
|
++_isEvaluating; |
|
|
|
|
|
|
|
@ -894,10 +894,9 @@ namespace Avalonia.PropertyStore |
|
|
|
{ |
|
|
|
var entry = frame.GetEntry(j); |
|
|
|
var property = entry.Property; |
|
|
|
|
|
|
|
// Skip if we already have a value/base value for this property.
|
|
|
|
if (_effectiveValues.TryGetValue(property, out var effectiveValue) && |
|
|
|
effectiveValue.BasePriority < BindingPriority.Unset) |
|
|
|
_effectiveValues.TryGetValue(property, out var effectiveValue); |
|
|
|
|
|
|
|
if (!HasHigherPriority(entry, priority, effectiveValue, changedValueEntry)) |
|
|
|
continue; |
|
|
|
|
|
|
|
if (!entry.HasValue) |
|
|
|
@ -942,6 +941,37 @@ namespace Avalonia.PropertyStore |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
private static bool HasHigherPriority( |
|
|
|
IValueEntry entry, |
|
|
|
BindingPriority entryPriority, |
|
|
|
EffectiveValue? current, |
|
|
|
IValueEntry? changedValueEntry) |
|
|
|
{ |
|
|
|
// Set the value if: there is no current effective value; or
|
|
|
|
if (current is null) |
|
|
|
return true; |
|
|
|
|
|
|
|
// The value's priority is higher than the current effective value's priority; or
|
|
|
|
if (entryPriority < current.Priority && entryPriority < current.BasePriority) |
|
|
|
return true; |
|
|
|
|
|
|
|
// - The value's priority is equal to the current effective value's priority
|
|
|
|
// - But the effective value was set via SetCurrentValue
|
|
|
|
// - As long as the SetCurrentValue wasn't overriding the value from the value entry under consideration
|
|
|
|
// - Or if it was, the value entry under consideration has changed; or
|
|
|
|
if (entryPriority == current.Priority && |
|
|
|
current.IsOverridenCurrentValue && |
|
|
|
(current.ValueEntry != entry || entry == changedValueEntry)) |
|
|
|
return true; |
|
|
|
|
|
|
|
// The value is a non-animation value and its priority is higher than the current effective value's base
|
|
|
|
// priority.
|
|
|
|
if (entryPriority > BindingPriority.Animation && entryPriority < current.BasePriority) |
|
|
|
return true; |
|
|
|
|
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
private bool TryGetEffectiveValue( |
|
|
|
AvaloniaProperty property, |
|
|
|
[NotNullWhen(true)] out EffectiveValue? value) |
|
|
|
|