|
|
@@ -259,6 +259,21 @@ namespace Avalonia
|
|
|
return registered.InvokeGetter(this);
|
|
|
}
|
|
|
|
|
|
+ /// <inheritdoc/>
|
|
|
+ public Optional<T> GetBaseValue<T>(StyledPropertyBase<T> property, BindingPriority maxPriority)
|
|
|
+ {
|
|
|
+ property = property ?? throw new ArgumentNullException(nameof(property));
|
|
|
+ VerifyAccess();
|
|
|
+
|
|
|
+ if (_values is object &&
|
|
|
+ _values.TryGetValue(property, maxPriority, out var value))
|
|
|
+ {
|
|
|
+ return value;
|
|
|
+ }
|
|
|
+
|
|
|
+ return default;
|
|
|
+ }
|
|
|
+
|
|
|
/// <summary>
|
|
|
/// Checks whether a <see cref="AvaloniaProperty"/> is animating.
|
|
|
/// </summary>
|
|
|
@@ -458,29 +473,43 @@ namespace Avalonia
|
|
|
return _propertyChanged?.GetInvocationList();
|
|
|
}
|
|
|
|
|
|
- void IValueSink.ValueChanged<T>(
|
|
|
- StyledPropertyBase<T> property,
|
|
|
- BindingPriority priority,
|
|
|
- Optional<T> oldValue,
|
|
|
- BindingValue<T> newValue)
|
|
|
+ void IValueSink.ValueChanged<T>(AvaloniaPropertyChangedEventArgs<T> change)
|
|
|
{
|
|
|
- oldValue = oldValue.HasValue ? oldValue : GetInheritedOrDefault(property);
|
|
|
- newValue = newValue.HasValue ? newValue : newValue.WithValue(GetInheritedOrDefault(property));
|
|
|
+ var property = (StyledPropertyBase<T>)change.Property;
|
|
|
|
|
|
- LogIfError(property, newValue);
|
|
|
+ LogIfError(property, change.NewValue);
|
|
|
|
|
|
- if (!EqualityComparer<T>.Default.Equals(oldValue.Value, newValue.Value))
|
|
|
+ // If the change is to the effective value of the property and no old/new value is set
|
|
|
+ // then fill in the old/new value from property inheritance/default value. We don't do
|
|
|
+ // this for non-effective value changes because these are only needed for property
|
|
|
+ // transitions, where knowing e.g. that an inherited value is active at an arbitrary
|
|
|
+ // priority isn't of any use and would introduce overhead.
|
|
|
+ if (change.IsEffectiveValueChange && !change.OldValue.HasValue)
|
|
|
{
|
|
|
- RaisePropertyChanged(property, oldValue, newValue, priority);
|
|
|
+ change.SetOldValue(GetInheritedOrDefault<T>(property));
|
|
|
+ }
|
|
|
|
|
|
- Logger.TryGet(LogEventLevel.Verbose)?.Log(
|
|
|
- LogArea.Property,
|
|
|
- this,
|
|
|
- "{Property} changed from {$Old} to {$Value} with priority {Priority}",
|
|
|
- property,
|
|
|
- oldValue,
|
|
|
- newValue,
|
|
|
- (BindingPriority)priority);
|
|
|
+ if (change.IsEffectiveValueChange && !change.NewValue.HasValue)
|
|
|
+ {
|
|
|
+ change.SetNewValue(GetInheritedOrDefault(property));
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!change.IsEffectiveValueChange ||
|
|
|
+ !EqualityComparer<T>.Default.Equals(change.OldValue.Value, change.NewValue.Value))
|
|
|
+ {
|
|
|
+ RaisePropertyChanged(change);
|
|
|
+
|
|
|
+ if (change.IsEffectiveValueChange)
|
|
|
+ {
|
|
|
+ Logger.TryGet(LogEventLevel.Verbose)?.Log(
|
|
|
+ LogArea.Property,
|
|
|
+ this,
|
|
|
+ "{Property} changed from {$Old} to {$Value} with priority {Priority}",
|
|
|
+ property,
|
|
|
+ change.OldValue,
|
|
|
+ change.NewValue,
|
|
|
+ change.Priority);
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -489,7 +518,13 @@ namespace Avalonia
|
|
|
IPriorityValueEntry entry,
|
|
|
Optional<T> oldValue)
|
|
|
{
|
|
|
- ((IValueSink)this).ValueChanged(property, BindingPriority.Unset, oldValue, default);
|
|
|
+ var change = new AvaloniaPropertyChangedEventArgs<T>(
|
|
|
+ this,
|
|
|
+ property,
|
|
|
+ oldValue,
|
|
|
+ default,
|
|
|
+ BindingPriority.Unset);
|
|
|
+ ((IValueSink)this).ValueChanged(change);
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
@@ -575,15 +610,20 @@ namespace Avalonia
|
|
|
/// <summary>
|
|
|
/// Called when a avalonia property changes on the object.
|
|
|
/// </summary>
|
|
|
- /// <param name="property">The property whose value has changed.</param>
|
|
|
- /// <param name="oldValue">The old value of the property.</param>
|
|
|
- /// <param name="newValue">The new value of the property.</param>
|
|
|
- /// <param name="priority">The priority of the new value.</param>
|
|
|
- protected virtual void OnPropertyChanged<T>(
|
|
|
- AvaloniaProperty<T> property,
|
|
|
- Optional<T> oldValue,
|
|
|
- BindingValue<T> newValue,
|
|
|
- BindingPriority priority)
|
|
|
+ /// <param name="change">The property change details.</param>
|
|
|
+ protected virtual void OnPropertyChangedCore<T>(AvaloniaPropertyChangedEventArgs<T> change)
|
|
|
+ {
|
|
|
+ if (change.IsEffectiveValueChange)
|
|
|
+ {
|
|
|
+ OnPropertyChanged(change);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// Called when a avalonia property changes on the object.
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="change">The property change details.</param>
|
|
|
+ protected virtual void OnPropertyChanged<T>(AvaloniaPropertyChangedEventArgs<T> change)
|
|
|
{
|
|
|
}
|
|
|
|
|
|
@@ -600,57 +640,12 @@ namespace Avalonia
|
|
|
BindingValue<T> newValue,
|
|
|
BindingPriority priority = BindingPriority.LocalValue)
|
|
|
{
|
|
|
- property = property ?? throw new ArgumentNullException(nameof(property));
|
|
|
-
|
|
|
- VerifyAccess();
|
|
|
-
|
|
|
- property.Notifying?.Invoke(this, true);
|
|
|
-
|
|
|
- try
|
|
|
- {
|
|
|
- AvaloniaPropertyChangedEventArgs<T> e = null;
|
|
|
- var hasChanged = property.HasChangedSubscriptions;
|
|
|
-
|
|
|
- if (hasChanged || _propertyChanged != null)
|
|
|
- {
|
|
|
- e = new AvaloniaPropertyChangedEventArgs<T>(
|
|
|
- this,
|
|
|
- property,
|
|
|
- oldValue,
|
|
|
- newValue,
|
|
|
- priority);
|
|
|
- }
|
|
|
-
|
|
|
- OnPropertyChanged(property, oldValue, newValue, priority);
|
|
|
-
|
|
|
- if (hasChanged)
|
|
|
- {
|
|
|
- property.NotifyChanged(e);
|
|
|
- }
|
|
|
-
|
|
|
- _propertyChanged?.Invoke(this, e);
|
|
|
-
|
|
|
- if (_inpcChanged != null)
|
|
|
- {
|
|
|
- var inpce = new PropertyChangedEventArgs(property.Name);
|
|
|
- _inpcChanged(this, inpce);
|
|
|
- }
|
|
|
-
|
|
|
- if (property.Inherits && _inheritanceChildren != null)
|
|
|
- {
|
|
|
- foreach (var child in _inheritanceChildren)
|
|
|
- {
|
|
|
- child.InheritedPropertyChanged(
|
|
|
- property,
|
|
|
- oldValue,
|
|
|
- newValue.ToOptional());
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- finally
|
|
|
- {
|
|
|
- property.Notifying?.Invoke(this, false);
|
|
|
- }
|
|
|
+ RaisePropertyChanged(new AvaloniaPropertyChangedEventArgs<T>(
|
|
|
+ this,
|
|
|
+ property,
|
|
|
+ oldValue,
|
|
|
+ newValue,
|
|
|
+ priority));
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
@@ -689,7 +684,9 @@ namespace Avalonia
|
|
|
return property.GetDefaultValue(GetType());
|
|
|
}
|
|
|
|
|
|
- private T GetValueOrInheritedOrDefault<T>(StyledPropertyBase<T> property)
|
|
|
+ private T GetValueOrInheritedOrDefault<T>(
|
|
|
+ StyledPropertyBase<T> property,
|
|
|
+ BindingPriority maxPriority = BindingPriority.Animation)
|
|
|
{
|
|
|
var o = this;
|
|
|
var inherits = property.Inherits;
|
|
|
@@ -699,7 +696,7 @@ namespace Avalonia
|
|
|
{
|
|
|
var values = o._values;
|
|
|
|
|
|
- if (values?.TryGetValue(property, out value) == true)
|
|
|
+ if (values?.TryGetValue(property, maxPriority, out value) == true)
|
|
|
{
|
|
|
return value;
|
|
|
}
|
|
|
@@ -715,6 +712,45 @@ namespace Avalonia
|
|
|
return property.GetDefaultValue(GetType());
|
|
|
}
|
|
|
|
|
|
+ protected internal void RaisePropertyChanged<T>(AvaloniaPropertyChangedEventArgs<T> change)
|
|
|
+ {
|
|
|
+ VerifyAccess();
|
|
|
+
|
|
|
+ change.Property.Notifying?.Invoke(this, true);
|
|
|
+
|
|
|
+ try
|
|
|
+ {
|
|
|
+ OnPropertyChangedCore(change);
|
|
|
+
|
|
|
+ if (change.IsEffectiveValueChange)
|
|
|
+ {
|
|
|
+ change.Property.NotifyChanged(change);
|
|
|
+ _propertyChanged?.Invoke(this, change);
|
|
|
+
|
|
|
+ if (_inpcChanged != null)
|
|
|
+ {
|
|
|
+ var inpce = new PropertyChangedEventArgs(change.Property.Name);
|
|
|
+ _inpcChanged(this, inpce);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (change.Property.Inherits && _inheritanceChildren != null)
|
|
|
+ {
|
|
|
+ foreach (var child in _inheritanceChildren)
|
|
|
+ {
|
|
|
+ child.InheritedPropertyChanged(
|
|
|
+ change.Property,
|
|
|
+ change.OldValue,
|
|
|
+ change.NewValue.ToOptional());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ finally
|
|
|
+ {
|
|
|
+ change.Property.Notifying?.Invoke(this, false);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
/// <summary>
|
|
|
/// Sets the value of a direct property.
|
|
|
/// </summary>
|