diff --git a/src/Avalonia.Animation/Animatable.cs b/src/Avalonia.Animation/Animatable.cs
index fa1e955153..9e9b84537b 100644
--- a/src/Avalonia.Animation/Animatable.cs
+++ b/src/Avalonia.Animation/Animatable.cs
@@ -1,10 +1,10 @@
using System;
+using System.Collections;
using System.Collections.Generic;
-using System.Linq;
-using System.Reactive.Linq;
-using Avalonia.Collections;
+using System.Collections.Specialized;
using Avalonia.Data;
-using Avalonia.Animation.Animators;
+
+#nullable enable
namespace Avalonia.Animation
{
@@ -13,9 +13,24 @@ namespace Avalonia.Animation
///
public class Animatable : AvaloniaObject
{
+ ///
+ /// Defines the property.
+ ///
public static readonly StyledProperty ClockProperty =
AvaloniaProperty.Register(nameof(Clock), inherits: true);
+ ///
+ /// Defines the property.
+ ///
+ public static readonly StyledProperty TransitionsProperty =
+ AvaloniaProperty.Register(nameof(Transitions));
+
+ private bool _transitionsEnabled = true;
+ private Dictionary? _transitionState;
+
+ ///
+ /// Gets or sets the clock which controls the animations on the control.
+ ///
public IClock Clock
{
get => GetValue(ClockProperty);
@@ -23,72 +38,194 @@ namespace Avalonia.Animation
}
///
- /// Defines the property.
+ /// Gets or sets the property transitions for the control.
///
- public static readonly DirectProperty TransitionsProperty =
- AvaloniaProperty.RegisterDirect(
- nameof(Transitions),
- o => o.Transitions,
- (o, v) => o.Transitions = v);
+ public Transitions? Transitions
+ {
+ get => GetValue(TransitionsProperty);
+ set => SetValue(TransitionsProperty, value);
+ }
- private Transitions _transitions;
+ ///
+ /// Enables transitions for the control.
+ ///
+ ///
+ /// This method should not be called from user code, it will be called automatically by the framework
+ /// when a control is added to the visual tree.
+ ///
+ protected void EnableTransitions()
+ {
+ if (!_transitionsEnabled)
+ {
+ _transitionsEnabled = true;
- private Dictionary _previousTransitions;
+ if (Transitions is object)
+ {
+ AddTransitions(Transitions);
+ }
+ }
+ }
///
- /// Gets or sets the property transitions for the control.
+ /// Disables transitions for the control.
///
- public Transitions Transitions
+ ///
+ /// This method should not be called from user code, it will be called automatically by the framework
+ /// when a control is added to the visual tree.
+ ///
+ protected void DisableTransitions()
+ {
+ if (_transitionsEnabled)
+ {
+ _transitionsEnabled = false;
+
+ if (Transitions is object)
+ {
+ RemoveTransitions(Transitions);
+ }
+ }
+ }
+
+ protected sealed override void OnPropertyChangedCore(AvaloniaPropertyChangedEventArgs change)
{
- get
+ if (change.Property == TransitionsProperty && change.IsEffectiveValueChange)
{
- if (_transitions is null)
- _transitions = new Transitions();
+ var oldTransitions = change.OldValue.GetValueOrDefault();
+ var newTransitions = change.NewValue.GetValueOrDefault();
- if (_previousTransitions is null)
- _previousTransitions = new Dictionary();
+ if (oldTransitions is object)
+ {
+ oldTransitions.CollectionChanged -= TransitionsCollectionChanged;
+ RemoveTransitions(oldTransitions);
+ }
- return _transitions;
+ if (newTransitions is object)
+ {
+ newTransitions.CollectionChanged += TransitionsCollectionChanged;
+ AddTransitions(newTransitions);
+ }
}
- set
+ else if (_transitionsEnabled &&
+ Transitions is object &&
+ _transitionState is object &&
+ !change.Property.IsDirect &&
+ change.Priority > BindingPriority.Animation)
{
- if (value is null)
- return;
+ foreach (var transition in Transitions)
+ {
+ if (transition.Property == change.Property)
+ {
+ var state = _transitionState[transition];
+ var oldValue = state.BaseValue;
+ var newValue = GetAnimationBaseValue(transition.Property);
- if (_previousTransitions is null)
- _previousTransitions = new Dictionary();
+ if (!Equals(oldValue, newValue))
+ {
+ state.BaseValue = newValue;
- SetAndRaise(TransitionsProperty, ref _transitions, value);
+ // We need to transition from the current animated value if present,
+ // instead of the old base value.
+ var animatedValue = GetValue(transition.Property);
+
+ if (!Equals(newValue, animatedValue))
+ {
+ oldValue = animatedValue;
+ }
+
+ state.Instance?.Dispose();
+ state.Instance = transition.Apply(
+ this,
+ Clock ?? AvaloniaLocator.Current.GetService(),
+ oldValue,
+ newValue);
+ return;
+ }
+ }
+ }
+ }
+
+ base.OnPropertyChangedCore(change);
+ }
+
+ private void TransitionsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
+ {
+ if (!_transitionsEnabled)
+ {
+ return;
+ }
+
+ switch (e.Action)
+ {
+ case NotifyCollectionChangedAction.Add:
+ AddTransitions(e.NewItems);
+ break;
+ case NotifyCollectionChangedAction.Remove:
+ RemoveTransitions(e.OldItems);
+ break;
+ case NotifyCollectionChangedAction.Replace:
+ RemoveTransitions(e.OldItems);
+ AddTransitions(e.NewItems);
+ break;
+ case NotifyCollectionChangedAction.Reset:
+ throw new NotSupportedException("Transitions collection cannot be reset.");
}
}
- protected override void OnPropertyChanged(
- AvaloniaProperty property,
- Optional oldValue,
- BindingValue newValue,
- BindingPriority priority)
+ private void AddTransitions(IList items)
{
- if (_transitions is null || _previousTransitions is null || priority == BindingPriority.Animation)
+ if (!_transitionsEnabled)
+ {
return;
+ }
+
+ _transitionState ??= new Dictionary();
- // PERF-SENSITIVE: Called on every property change. Don't use LINQ here (too many allocations).
- foreach (var transition in _transitions)
+ for (var i = 0; i < items.Count; ++i)
{
- if (transition.Property == property)
+ var t = (ITransition)items[i];
+
+ _transitionState.Add(t, new TransitionState
{
- if (_previousTransitions.TryGetValue(property, out var dispose))
- dispose.Dispose();
+ BaseValue = GetAnimationBaseValue(t.Property),
+ });
+ }
+ }
- var instance = transition.Apply(
- this,
- Clock ?? Avalonia.Animation.Clock.GlobalClock,
- oldValue.GetValueOrDefault(),
- newValue.GetValueOrDefault());
+ private void RemoveTransitions(IList items)
+ {
+ if (_transitionState is null)
+ {
+ return;
+ }
- _previousTransitions[property] = instance;
- return;
+ for (var i = 0; i < items.Count; ++i)
+ {
+ var t = (ITransition)items[i];
+
+ if (_transitionState.TryGetValue(t, out var state))
+ {
+ state.Instance?.Dispose();
+ _transitionState.Remove(t);
}
}
}
+
+ private object GetAnimationBaseValue(AvaloniaProperty property)
+ {
+ var value = this.GetBaseValue(property, BindingPriority.LocalValue);
+
+ if (value == AvaloniaProperty.UnsetValue)
+ {
+ value = GetValue(property);
+ }
+
+ return value;
+ }
+
+ private class TransitionState
+ {
+ public IDisposable? Instance { get; set; }
+ public object? BaseValue { get; set; }
+ }
}
}
diff --git a/src/Avalonia.Animation/TransitionInstance.cs b/src/Avalonia.Animation/TransitionInstance.cs
index efbbed51b5..ad2001d621 100644
--- a/src/Avalonia.Animation/TransitionInstance.cs
+++ b/src/Avalonia.Animation/TransitionInstance.cs
@@ -19,6 +19,8 @@ namespace Avalonia.Animation
public TransitionInstance(IClock clock, TimeSpan Duration)
{
+ clock = clock ?? throw new ArgumentNullException(nameof(clock));
+
_duration = Duration;
_baseClock = clock;
}
diff --git a/src/Avalonia.Animation/Transitions.cs b/src/Avalonia.Animation/Transitions.cs
index 2741039ebc..6687a2902d 100644
--- a/src/Avalonia.Animation/Transitions.cs
+++ b/src/Avalonia.Animation/Transitions.cs
@@ -1,4 +1,6 @@
+using System;
using Avalonia.Collections;
+using Avalonia.Threading;
namespace Avalonia.Animation
{
@@ -13,6 +15,17 @@ namespace Avalonia.Animation
public Transitions()
{
ResetBehavior = ResetBehavior.Remove;
+ Validate = ValidateTransition;
+ }
+
+ private void ValidateTransition(ITransition obj)
+ {
+ Dispatcher.UIThread.VerifyAccess();
+
+ if (obj.Property.IsDirect)
+ {
+ throw new InvalidOperationException("Cannot animate a direct property.");
+ }
}
}
}
diff --git a/src/Avalonia.Base/AvaloniaObject.cs b/src/Avalonia.Base/AvaloniaObject.cs
index ed36e6da43..f387d7e0b6 100644
--- a/src/Avalonia.Base/AvaloniaObject.cs
+++ b/src/Avalonia.Base/AvaloniaObject.cs
@@ -259,6 +259,21 @@ namespace Avalonia
return registered.InvokeGetter(this);
}
+ ///
+ public Optional GetBaseValue(StyledPropertyBase 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;
+ }
+
///
/// Checks whether a is animating.
///
@@ -458,29 +473,43 @@ namespace Avalonia
return _propertyChanged?.GetInvocationList();
}
- void IValueSink.ValueChanged(
- StyledPropertyBase property,
- BindingPriority priority,
- Optional oldValue,
- BindingValue newValue)
+ void IValueSink.ValueChanged(AvaloniaPropertyChangedEventArgs change)
{
- oldValue = oldValue.HasValue ? oldValue : GetInheritedOrDefault(property);
- newValue = newValue.HasValue ? newValue : newValue.WithValue(GetInheritedOrDefault(property));
+ var property = (StyledPropertyBase)change.Property;
- LogIfError(property, newValue);
+ LogIfError(property, change.NewValue);
- if (!EqualityComparer.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(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.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 oldValue)
{
- ((IValueSink)this).ValueChanged(property, BindingPriority.Unset, oldValue, default);
+ var change = new AvaloniaPropertyChangedEventArgs(
+ this,
+ property,
+ oldValue,
+ default,
+ BindingPriority.Unset);
+ ((IValueSink)this).ValueChanged(change);
}
///
@@ -575,15 +610,20 @@ namespace Avalonia
///
/// Called when a avalonia property changes on the object.
///
- /// The property whose value has changed.
- /// The old value of the property.
- /// The new value of the property.
- /// The priority of the new value.
- protected virtual void OnPropertyChanged(
- AvaloniaProperty property,
- Optional oldValue,
- BindingValue newValue,
- BindingPriority priority)
+ /// The property change details.
+ protected virtual void OnPropertyChangedCore(AvaloniaPropertyChangedEventArgs change)
+ {
+ if (change.IsEffectiveValueChange)
+ {
+ OnPropertyChanged(change);
+ }
+ }
+
+ ///
+ /// Called when a avalonia property changes on the object.
+ ///
+ /// The property change details.
+ protected virtual void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
}
@@ -600,57 +640,12 @@ namespace Avalonia
BindingValue newValue,
BindingPriority priority = BindingPriority.LocalValue)
{
- property = property ?? throw new ArgumentNullException(nameof(property));
-
- VerifyAccess();
-
- property.Notifying?.Invoke(this, true);
-
- try
- {
- AvaloniaPropertyChangedEventArgs e = null;
- var hasChanged = property.HasChangedSubscriptions;
-
- if (hasChanged || _propertyChanged != null)
- {
- e = new AvaloniaPropertyChangedEventArgs(
- 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(
+ this,
+ property,
+ oldValue,
+ newValue,
+ priority));
}
///
@@ -689,7 +684,9 @@ namespace Avalonia
return property.GetDefaultValue(GetType());
}
- private T GetValueOrInheritedOrDefault(StyledPropertyBase property)
+ private T GetValueOrInheritedOrDefault(
+ StyledPropertyBase 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,51 @@ namespace Avalonia
return property.GetDefaultValue(GetType());
}
+ protected internal void RaisePropertyChanged(AvaloniaPropertyChangedEventArgs change)
+ {
+ VerifyAccess();
+
+ if (change.IsEffectiveValueChange)
+ {
+ 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
+ {
+ if (change.IsEffectiveValueChange)
+ {
+ change.Property.Notifying?.Invoke(this, false);
+ }
+ }
+ }
+
///
/// Sets the value of a direct property.
///
diff --git a/src/Avalonia.Base/AvaloniaObjectExtensions.cs b/src/Avalonia.Base/AvaloniaObjectExtensions.cs
index 4fc65a3ed4..173c5c1a94 100644
--- a/src/Avalonia.Base/AvaloniaObjectExtensions.cs
+++ b/src/Avalonia.Base/AvaloniaObjectExtensions.cs
@@ -448,6 +448,65 @@ namespace Avalonia
};
}
+ ///
+ /// Gets an base value.
+ ///
+ /// The object.
+ /// The property.
+ /// The maximum priority for the value.
+ ///
+ /// For styled properties, gets the value of the property if set on the object with a
+ /// priority equal or lower to , otherwise
+ /// . Note that this method does not return
+ /// property values that come from inherited or default values.
+ ///
+ /// For direct properties returns .
+ ///
+ public static object GetBaseValue(
+ this IAvaloniaObject target,
+ AvaloniaProperty property,
+ BindingPriority maxPriority)
+ {
+ target = target ?? throw new ArgumentNullException(nameof(target));
+ property = property ?? throw new ArgumentNullException(nameof(property));
+
+ return property.RouteGetBaseValue(target, maxPriority);
+ }
+
+ ///
+ /// Gets an base value.
+ ///
+ /// The object.
+ /// The property.
+ /// The maximum priority for the value.
+ ///
+ /// For styled properties, gets the value of the property if set on the object with a
+ /// priority equal or lower to , otherwise
+ /// . Note that this method does not return property values
+ /// that come from inherited or default values.
+ ///
+ /// For direct properties returns
+ /// .
+ ///
+ public static Optional GetBaseValue(
+ this IAvaloniaObject target,
+ AvaloniaProperty property,
+ BindingPriority maxPriority)
+ {
+ target = target ?? throw new ArgumentNullException(nameof(target));
+ property = property ?? throw new ArgumentNullException(nameof(property));
+
+ target = target ?? throw new ArgumentNullException(nameof(target));
+ property = property ?? throw new ArgumentNullException(nameof(property));
+
+ return property switch
+ {
+ StyledPropertyBase styled => target.GetBaseValue(styled, maxPriority),
+ DirectPropertyBase direct => target.GetValue(direct),
+ _ => throw new NotSupportedException("Unsupported AvaloniaProperty type.")
+ };
+ }
+
///
/// Sets a value.
///
diff --git a/src/Avalonia.Base/AvaloniaProperty.cs b/src/Avalonia.Base/AvaloniaProperty.cs
index 74d7039751..daa7191cc5 100644
--- a/src/Avalonia.Base/AvaloniaProperty.cs
+++ b/src/Avalonia.Base/AvaloniaProperty.cs
@@ -496,6 +496,13 @@ namespace Avalonia
/// The object instance.
internal abstract object RouteGetValue(IAvaloniaObject o);
+ ///
+ /// Routes an untyped GetBaseValue call to a typed call.
+ ///
+ /// The object instance.
+ /// The maximum priority for the value.
+ internal abstract object RouteGetBaseValue(IAvaloniaObject o, BindingPriority maxPriority);
+
///
/// Routes an untyped SetValue call to a typed call.
///
diff --git a/src/Avalonia.Base/AvaloniaPropertyChangedEventArgs.cs b/src/Avalonia.Base/AvaloniaPropertyChangedEventArgs.cs
index 0f09747865..c1a2832fde 100644
--- a/src/Avalonia.Base/AvaloniaPropertyChangedEventArgs.cs
+++ b/src/Avalonia.Base/AvaloniaPropertyChangedEventArgs.cs
@@ -16,6 +16,7 @@ namespace Avalonia
{
Sender = sender;
Priority = priority;
+ IsEffectiveValueChange = true;
}
///
@@ -35,19 +36,11 @@ namespace Avalonia
///
/// Gets the old value of the property.
///
- ///
- /// The old value of the property or if the
- /// property previously had no value.
- ///
public object? OldValue => GetOldValue();
///
/// Gets the new value of the property.
///
- ///
- /// The new value of the property or if the
- /// property previously had no value.
- ///
public object? NewValue => GetNewValue();
///
@@ -58,6 +51,20 @@ namespace Avalonia
///
public BindingPriority Priority { get; private set; }
+ ///
+ /// Gets a value indicating whether the change represents a change to the effective value of
+ /// the property.
+ ///
+ ///
+ /// This will usually be true, except in
+ ///
+ /// which recieves notifications for all changes to property values, whether a value with a higher
+ /// priority is present or not. When this property is false, the change that is being signalled
+ /// has not resulted in a change to the property value on the object.
+ ///
+ public bool IsEffectiveValueChange { get; private set; }
+
+ internal void MarkNonEffectiveValue() => IsEffectiveValueChange = false;
protected abstract AvaloniaProperty GetProperty();
protected abstract object? GetOldValue();
protected abstract object? GetNewValue();
diff --git a/src/Avalonia.Base/AvaloniaPropertyChangedEventArgs`1.cs b/src/Avalonia.Base/AvaloniaPropertyChangedEventArgs`1.cs
index fca32b4ffc..054bf93b3a 100644
--- a/src/Avalonia.Base/AvaloniaPropertyChangedEventArgs`1.cs
+++ b/src/Avalonia.Base/AvaloniaPropertyChangedEventArgs`1.cs
@@ -1,4 +1,3 @@
-using System;
using Avalonia.Data;
#nullable enable
@@ -6,7 +5,7 @@ using Avalonia.Data;
namespace Avalonia
{
///
- /// Provides information for a avalonia property change.
+ /// Provides information for an Avalonia property change.
///
public class AvaloniaPropertyChangedEventArgs : AvaloniaPropertyChangedEventArgs
{
@@ -42,19 +41,28 @@ namespace Avalonia
///
/// Gets the old value of the property.
///
- ///
- /// The old value of the property.
- ///
+ ///
+ /// When is true, returns the
+ /// old value of the property on the object.
+ /// When is false, returns
+ /// .
+ ///
public new Optional OldValue { get; private set; }
///
/// Gets the new value of the property.
///
- ///
- /// The new value of the property.
- ///
+ ///
+ /// When is true, returns the
+ /// value of the property on the object.
+ /// When is false returns the
+ /// changed value, or if the value was removed.
+ ///
public new BindingValue NewValue { get; private set; }
+ internal void SetOldValue(Optional value) => OldValue = value;
+ internal void SetNewValue(BindingValue value) => NewValue = value;
+
protected override AvaloniaProperty GetProperty() => Property;
protected override object? GetOldValue() => OldValue.GetValueOrDefault(AvaloniaProperty.UnsetValue);
diff --git a/src/Avalonia.Base/Data/BindingValue.cs b/src/Avalonia.Base/Data/BindingValue.cs
index cecdd33e7b..9aac1bacba 100644
--- a/src/Avalonia.Base/Data/BindingValue.cs
+++ b/src/Avalonia.Base/Data/BindingValue.cs
@@ -348,8 +348,8 @@ namespace Avalonia.Data
return new BindingValue(
fallbackValue.HasValue ?
- BindingValueType.DataValidationError :
- BindingValueType.DataValidationErrorWithFallback,
+ BindingValueType.DataValidationErrorWithFallback :
+ BindingValueType.DataValidationError,
fallbackValue.HasValue ? fallbackValue.Value : default,
e);
}
diff --git a/src/Avalonia.Base/DirectPropertyBase.cs b/src/Avalonia.Base/DirectPropertyBase.cs
index d3b5277c53..0e65379abd 100644
--- a/src/Avalonia.Base/DirectPropertyBase.cs
+++ b/src/Avalonia.Base/DirectPropertyBase.cs
@@ -120,6 +120,11 @@ namespace Avalonia
return o.GetValue(this);
}
+ internal override object RouteGetBaseValue(IAvaloniaObject o, BindingPriority maxPriority)
+ {
+ return o.GetValue(this);
+ }
+
///
internal override IDisposable? RouteSetValue(
IAvaloniaObject o,
diff --git a/src/Avalonia.Base/IAvaloniaObject.cs b/src/Avalonia.Base/IAvaloniaObject.cs
index 867249bf0e..0452f77d4c 100644
--- a/src/Avalonia.Base/IAvaloniaObject.cs
+++ b/src/Avalonia.Base/IAvaloniaObject.cs
@@ -41,6 +41,19 @@ namespace Avalonia
/// The value.
T GetValue(DirectPropertyBase property);
+ ///
+ /// Gets an base value.
+ ///
+ /// The type of the property.
+ /// The property.
+ /// The maximum priority for the value.
+ ///
+ /// Gets the value of the property, if set on this object with a priority equal or lower to
+ /// , otherwise . Note that
+ /// this method does not return property values that come from inherited or default values.
+ ///
+ Optional GetBaseValue(StyledPropertyBase property, BindingPriority maxPriority);
+
///
/// Checks whether a is animating.
///
diff --git a/src/Avalonia.Base/PropertyStore/BindingEntry.cs b/src/Avalonia.Base/PropertyStore/BindingEntry.cs
index 3249b31d66..0d563947e7 100644
--- a/src/Avalonia.Base/PropertyStore/BindingEntry.cs
+++ b/src/Avalonia.Base/PropertyStore/BindingEntry.cs
@@ -22,6 +22,7 @@ namespace Avalonia.PropertyStore
private readonly IAvaloniaObject _owner;
private IValueSink _sink;
private IDisposable? _subscription;
+ private Optional _value;
public BindingEntry(
IAvaloniaObject owner,
@@ -40,18 +41,21 @@ namespace Avalonia.PropertyStore
public StyledPropertyBase Property { get; }
public BindingPriority Priority { get; }
public IObservable> Source { get; }
- public Optional Value { get; private set; }
- Optional
internal interface IValue
{
- Optional Value { get; }
- BindingPriority ValuePriority { get; }
+ Optional GetValue();
+ BindingPriority Priority { get; }
}
///
@@ -19,6 +19,6 @@ namespace Avalonia.PropertyStore
/// The property type.
internal interface IValue : IValue
{
- new Optional Value { get; }
+ Optional GetValue(BindingPriority maxPriority = BindingPriority.Animation);
}
}
diff --git a/src/Avalonia.Base/PropertyStore/IValueSink.cs b/src/Avalonia.Base/PropertyStore/IValueSink.cs
index 9012a985ac..3a1e9731d8 100644
--- a/src/Avalonia.Base/PropertyStore/IValueSink.cs
+++ b/src/Avalonia.Base/PropertyStore/IValueSink.cs
@@ -9,11 +9,7 @@ namespace Avalonia.PropertyStore
///
internal interface IValueSink
{
- void ValueChanged(
- StyledPropertyBase property,
- BindingPriority priority,
- Optional oldValue,
- BindingValue newValue);
+ void ValueChanged(AvaloniaPropertyChangedEventArgs change);
void Completed(
StyledPropertyBase property,
diff --git a/src/Avalonia.Base/PropertyStore/LocalValueEntry.cs b/src/Avalonia.Base/PropertyStore/LocalValueEntry.cs
index 22258390da..59c017bc09 100644
--- a/src/Avalonia.Base/PropertyStore/LocalValueEntry.cs
+++ b/src/Avalonia.Base/PropertyStore/LocalValueEntry.cs
@@ -14,9 +14,14 @@ namespace Avalonia.PropertyStore
private T _value;
public LocalValueEntry(T value) => _value = value;
- public Optional Value => _value;
- public BindingPriority ValuePriority => BindingPriority.LocalValue;
- Optional IValue.Value => Value.ToObject();
+ public BindingPriority Priority => BindingPriority.LocalValue;
+ Optional IValue.GetValue() => new Optional(_value);
+
+ public Optional GetValue(BindingPriority maxPriority)
+ {
+ return BindingPriority.LocalValue >= maxPriority ? _value : Optional.Empty;
+ }
+
public void SetValue(T value) => _value = value;
}
}
diff --git a/src/Avalonia.Base/PropertyStore/PriorityValue.cs b/src/Avalonia.Base/PropertyStore/PriorityValue.cs
index affb20f334..5e223cad60 100644
--- a/src/Avalonia.Base/PropertyStore/PriorityValue.cs
+++ b/src/Avalonia.Base/PropertyStore/PriorityValue.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.ComponentModel;
using Avalonia.Data;
#nullable enable
@@ -24,6 +25,7 @@ namespace Avalonia.PropertyStore
private readonly List> _entries = new List>();
private readonly Func? _coerceValue;
private Optional _localValue;
+ private Optional _value;
public PriorityValue(
IAvaloniaObject owner,
@@ -50,11 +52,13 @@ namespace Avalonia.PropertyStore
{
existing.Reparent(this);
_entries.Add(existing);
+
+ var v = existing.GetValue();
- if (existing.Value.HasValue)
+ if (v.HasValue)
{
- Value = existing.Value;
- ValuePriority = existing.Priority;
+ _value = v;
+ Priority = existing.Priority;
}
}
@@ -65,18 +69,39 @@ namespace Avalonia.PropertyStore
LocalValueEntry existing)
: this(owner, property, sink)
{
- _localValue = existing.Value;
- Value = _localValue;
- ValuePriority = BindingPriority.LocalValue;
+ _value = _localValue = existing.GetValue(BindingPriority.LocalValue);
+ Priority = BindingPriority.LocalValue;
}
public StyledPropertyBase Property { get; }
- public Optional Value { get; private set; }
- public BindingPriority ValuePriority { get; private set; }
+ public BindingPriority Priority { get; private set; } = BindingPriority.Unset;
public IReadOnlyList> Entries => _entries;
- Optional IValue.Value => Value.ToObject();
+ Optional IValue.GetValue() => _value.ToObject();
+
+ public void ClearLocalValue()
+ {
+ UpdateEffectiveValue(new AvaloniaPropertyChangedEventArgs(
+ _owner,
+ Property,
+ default,
+ default,
+ BindingPriority.LocalValue));
+ }
+
+ public Optional GetValue(BindingPriority maxPriority = BindingPriority.Animation)
+ {
+ if (Priority == BindingPriority.Unset)
+ {
+ return default;
+ }
- public void ClearLocalValue() => UpdateEffectiveValue();
+ if (Priority >= maxPriority)
+ {
+ return _value;
+ }
+
+ return CalculateValue(maxPriority).Item1;
+ }
public IDisposable? SetValue(T value, BindingPriority priority)
{
@@ -94,7 +119,13 @@ namespace Avalonia.PropertyStore
result = entry;
}
- UpdateEffectiveValue();
+ UpdateEffectiveValue(new AvaloniaPropertyChangedEventArgs(
+ _owner,
+ Property,
+ default,
+ value,
+ priority));
+
return result;
}
@@ -106,20 +137,19 @@ namespace Avalonia.PropertyStore
return binding;
}
- public void CoerceValue() => UpdateEffectiveValue();
+ public void CoerceValue() => UpdateEffectiveValue(null);
- void IValueSink.ValueChanged(
- StyledPropertyBase property,
- BindingPriority priority,
- Optional oldValue,
- BindingValue newValue)
+ void IValueSink.ValueChanged(AvaloniaPropertyChangedEventArgs change)
{
- if (priority == BindingPriority.LocalValue)
+ if (change.Priority == BindingPriority.LocalValue)
{
_localValue = default;
}
- UpdateEffectiveValue();
+ if (change is AvaloniaPropertyChangedEventArgs c)
+ {
+ UpdateEffectiveValue(c);
+ }
}
void IValueSink.Completed(
@@ -128,7 +158,16 @@ namespace Avalonia.PropertyStore
Optional oldValue)
{
_entries.Remove((IPriorityValueEntry)entry);
- UpdateEffectiveValue();
+
+ if (oldValue is Optional o)
+ {
+ UpdateEffectiveValue(new AvaloniaPropertyChangedEventArgs(
+ _owner,
+ Property,
+ o,
+ default,
+ entry.Priority));
+ }
}
private int FindInsertPoint(BindingPriority priority)
@@ -147,53 +186,73 @@ namespace Avalonia.PropertyStore
return result;
}
- private void UpdateEffectiveValue()
+ public (Optional, BindingPriority) CalculateValue(BindingPriority maxPriority)
{
var reachedLocalValues = false;
- var value = default(Optional);
- if (_entries.Count > 0)
+ for (var i = _entries.Count - 1; i >= 0; --i)
{
- for (var i = _entries.Count - 1; i >= 0; --i)
+ var entry = _entries[i];
+
+ if (entry.Priority < maxPriority)
+ {
+ continue;
+ }
+
+ if (!reachedLocalValues &&
+ entry.Priority >= BindingPriority.LocalValue &&
+ maxPriority <= BindingPriority.LocalValue &&
+ _localValue.HasValue)
+ {
+ return (_localValue, BindingPriority.LocalValue);
+ }
+
+ var entryValue = entry.GetValue();
+
+ if (entryValue.HasValue)
{
- var entry = _entries[i];
-
- if (!reachedLocalValues && entry.Priority >= BindingPriority.LocalValue)
- {
- reachedLocalValues = true;
-
- if (_localValue.HasValue)
- {
- value = _localValue;
- ValuePriority = BindingPriority.LocalValue;
- break;
- }
- }
-
- if (entry.Value.HasValue)
- {
- value = entry.Value;
- ValuePriority = entry.Priority;
- break;
- }
+ return (entryValue, entry.Priority);
}
}
- else if (_localValue.HasValue)
+
+ if (!reachedLocalValues &&
+ maxPriority <= BindingPriority.LocalValue &&
+ _localValue.HasValue)
{
- value = _localValue;
- ValuePriority = BindingPriority.LocalValue;
+ return (_localValue, BindingPriority.LocalValue);
}
+ return (default, BindingPriority.Unset);
+ }
+
+ private void UpdateEffectiveValue(AvaloniaPropertyChangedEventArgs? change)
+ {
+ var (value, priority) = CalculateValue(BindingPriority.Animation);
+
if (value.HasValue && _coerceValue != null)
{
value = _coerceValue(_owner, value.Value);
}
- if (value != Value)
+ Priority = priority;
+
+ if (value != _value)
+ {
+ var old = _value;
+ _value = value;
+
+ _sink.ValueChanged(new AvaloniaPropertyChangedEventArgs(
+ _owner,
+ Property,
+ old,
+ value,
+ Priority));
+ }
+ else if (change is object)
{
- var old = Value;
- Value = value;
- _sink.ValueChanged(Property, ValuePriority, old, value);
+ change.MarkNonEffectiveValue();
+ change.SetOldValue(default);
+ _sink.ValueChanged(change);
}
}
}
diff --git a/src/Avalonia.Base/StyledPropertyBase.cs b/src/Avalonia.Base/StyledPropertyBase.cs
index 1f88bfb2aa..3e92c3bdf7 100644
--- a/src/Avalonia.Base/StyledPropertyBase.cs
+++ b/src/Avalonia.Base/StyledPropertyBase.cs
@@ -197,6 +197,13 @@ namespace Avalonia
return o.GetValue(this);
}
+ ///
+ internal override object RouteGetBaseValue(IAvaloniaObject o, BindingPriority maxPriority)
+ {
+ var value = o.GetBaseValue(this, maxPriority);
+ return value.HasValue ? value.Value : AvaloniaProperty.UnsetValue;
+ }
+
///
internal override IDisposable RouteSetValue(
IAvaloniaObject o,
diff --git a/src/Avalonia.Base/ValueStore.cs b/src/Avalonia.Base/ValueStore.cs
index 104c06de0f..05e66f2e0a 100644
--- a/src/Avalonia.Base/ValueStore.cs
+++ b/src/Avalonia.Base/ValueStore.cs
@@ -37,7 +37,7 @@ namespace Avalonia
{
if (_values.TryGetValue(property, out var slot))
{
- return slot.ValuePriority < BindingPriority.LocalValue;
+ return slot.Priority < BindingPriority.LocalValue;
}
return false;
@@ -47,21 +47,24 @@ namespace Avalonia
{
if (_values.TryGetValue(property, out var slot))
{
- return slot.Value.HasValue;
+ return slot.GetValue().HasValue;
}
return false;
}
- public bool TryGetValue(StyledPropertyBase property, out T value)
+ public bool TryGetValue(
+ StyledPropertyBase property,
+ BindingPriority maxPriority,
+ out T value)
{
if (_values.TryGetValue(property, out var slot))
{
- var v = (IValue)slot;
+ var v = ((IValue)slot).GetValue(maxPriority);
- if (v.Value.HasValue)
+ if (v.HasValue)
{
- value = v.Value.Value;
+ value = v.Value;
return true;
}
}
@@ -90,17 +93,22 @@ namespace Avalonia
_values.AddValue(property, entry);
result = entry.SetValue(value, priority);
}
- else if (priority == BindingPriority.LocalValue)
- {
- _values.AddValue(property, new LocalValueEntry(value));
- _sink.ValueChanged(property, priority, default, value);
- }
else
{
- var entry = new ConstantValueEntry(property, value, priority, this);
- _values.AddValue(property, entry);
- _sink.ValueChanged(property, priority, default, value);
- result = entry;
+ var change = new AvaloniaPropertyChangedEventArgs(_owner, property, default, value, priority);
+
+ if (priority == BindingPriority.LocalValue)
+ {
+ _values.AddValue(property, new LocalValueEntry(value));
+ _sink.ValueChanged(change);
+ }
+ else
+ {
+ var entry = new ConstantValueEntry(property, value, priority, this);
+ _values.AddValue(property, entry);
+ _sink.ValueChanged(change);
+ result = entry;
+ }
}
return result;
@@ -149,13 +157,14 @@ namespace Avalonia
if (remove)
{
- var old = TryGetValue(property, out var value) ? value : default;
+ var old = TryGetValue(property, BindingPriority.LocalValue, out var value) ? value : default;
_values.Remove(property);
- _sink.ValueChanged(
+ _sink.ValueChanged(new AvaloniaPropertyChangedEventArgs(
+ _owner,
property,
- BindingPriority.Unset,
old,
- BindingValue.Unset);
+ default,
+ BindingPriority.Unset));
}
}
}
@@ -176,23 +185,20 @@ namespace Avalonia
{
if (_values.TryGetValue(property, out var slot))
{
+ var slotValue = slot.GetValue();
return new Diagnostics.AvaloniaPropertyValue(
property,
- slot.Value.HasValue ? slot.Value.Value : AvaloniaProperty.UnsetValue,
- slot.ValuePriority,
+ slotValue.HasValue ? slotValue.Value : AvaloniaProperty.UnsetValue,
+ slot.Priority,
null);
}
return null;
}
- void IValueSink.ValueChanged(
- StyledPropertyBase property,
- BindingPriority priority,
- Optional oldValue,
- BindingValue newValue)
+ void IValueSink.ValueChanged(AvaloniaPropertyChangedEventArgs change)
{
- _sink.ValueChanged(property, priority, oldValue, newValue);
+ _sink.ValueChanged(change);
}
void IValueSink.Completed(
@@ -232,9 +238,14 @@ namespace Avalonia
{
if (priority == BindingPriority.LocalValue)
{
- var old = l.Value;
+ var old = l.GetValue(BindingPriority.LocalValue);
l.SetValue(value);
- _sink.ValueChanged(property, priority, old, value);
+ _sink.ValueChanged(new AvaloniaPropertyChangedEventArgs(
+ _owner,
+ property,
+ old,
+ value,
+ priority));
}
else
{
diff --git a/src/Avalonia.Controls.DataGrid/DataGrid.cs b/src/Avalonia.Controls.DataGrid/DataGrid.cs
index 3a1e612a05..cfe47a09d5 100644
--- a/src/Avalonia.Controls.DataGrid/DataGrid.cs
+++ b/src/Avalonia.Controls.DataGrid/DataGrid.cs
@@ -1,5 +1,4 @@
-// (c) Copyright Microsoft Corporation.
-// This source is subject to the Microsoft Public License (Ms-PL).
+// This source is subject to the Microsoft Public License (Ms-PL).
// Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
// All other rights reserved.
@@ -767,7 +766,7 @@ namespace Avalonia.Controls
///
/// ItemsProperty property changed handler.
///
- /// AvaloniaPropertyChangedEventArgs.
+ /// The event arguments.
private void OnItemsPropertyChanged(AvaloniaPropertyChangedEventArgs e)
{
if (!_areHandlersSuspended)
diff --git a/src/Avalonia.Controls/Button.cs b/src/Avalonia.Controls/Button.cs
index 136e8ed851..b54eb2ac57 100644
--- a/src/Avalonia.Controls/Button.cs
+++ b/src/Avalonia.Controls/Button.cs
@@ -313,17 +313,13 @@ namespace Avalonia.Controls
IsPressed = false;
}
- protected override void OnPropertyChanged(
- AvaloniaProperty property,
- Optional oldValue,
- BindingValue newValue,
- BindingPriority priority)
+ protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
- base.OnPropertyChanged(property, oldValue, newValue, priority);
+ base.OnPropertyChanged(change);
- if (property == IsPressedProperty)
+ if (change.Property == IsPressedProperty)
{
- UpdatePseudoClasses(newValue.GetValueOrDefault());
+ UpdatePseudoClasses(change.NewValue.GetValueOrDefault());
}
}
diff --git a/src/Avalonia.Controls/ButtonSpinner.cs b/src/Avalonia.Controls/ButtonSpinner.cs
index 7945d63b06..44f66d397a 100644
--- a/src/Avalonia.Controls/ButtonSpinner.cs
+++ b/src/Avalonia.Controls/ButtonSpinner.cs
@@ -205,17 +205,13 @@ namespace Avalonia.Controls
}
}
- protected override void OnPropertyChanged(
- AvaloniaProperty property,
- Optional oldValue,
- BindingValue newValue,
- BindingPriority priority)
+ protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
- base.OnPropertyChanged(property, oldValue, newValue, priority);
+ base.OnPropertyChanged(change);
- if (property == ButtonSpinnerLocationProperty)
+ if (change.Property == ButtonSpinnerLocationProperty)
{
- UpdatePseudoClasses(newValue.GetValueOrDefault());
+ UpdatePseudoClasses(change.NewValue.GetValueOrDefault());
}
}
diff --git a/src/Avalonia.Controls/Calendar/DatePicker.cs b/src/Avalonia.Controls/Calendar/DatePicker.cs
index 7cd0230b36..0f53dc1364 100644
--- a/src/Avalonia.Controls/Calendar/DatePicker.cs
+++ b/src/Avalonia.Controls/Calendar/DatePicker.cs
@@ -510,17 +510,13 @@ namespace Avalonia.Controls
}
}
- protected override void OnPropertyChanged(
- AvaloniaProperty property,
- Optional oldValue,
- BindingValue newValue,
- BindingPriority priority)
+ protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
- base.OnPropertyChanged(property, oldValue, newValue, priority);
+ base.OnPropertyChanged(change);
- if (property == SelectedDateProperty)
+ if (change.Property == SelectedDateProperty)
{
- DataValidationErrors.SetError(this, newValue.Error);
+ DataValidationErrors.SetError(this, change.NewValue.Error);
}
}
diff --git a/src/Avalonia.Controls/Expander.cs b/src/Avalonia.Controls/Expander.cs
index e42d3ec1e5..43882b70c8 100644
--- a/src/Avalonia.Controls/Expander.cs
+++ b/src/Avalonia.Controls/Expander.cs
@@ -78,17 +78,13 @@ namespace Avalonia.Controls
}
}
- protected override void OnPropertyChanged(
- AvaloniaProperty property,
- Optional oldValue,
- BindingValue newValue,
- BindingPriority priority)
+ protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
- base.OnPropertyChanged(property, oldValue, newValue, priority);
+ base.OnPropertyChanged(change);
- if (property == ExpandDirectionProperty)
+ if (change.Property == ExpandDirectionProperty)
{
- UpdatePseudoClasses(newValue.GetValueOrDefault());
+ UpdatePseudoClasses(change.NewValue.GetValueOrDefault());
}
}
diff --git a/src/Avalonia.Controls/Notifications/WindowNotificationManager.cs b/src/Avalonia.Controls/Notifications/WindowNotificationManager.cs
index 0cfea2c68b..6d9f6b8b77 100644
--- a/src/Avalonia.Controls/Notifications/WindowNotificationManager.cs
+++ b/src/Avalonia.Controls/Notifications/WindowNotificationManager.cs
@@ -136,17 +136,13 @@ namespace Avalonia.Controls.Notifications
notificationControl.Close();
}
- protected override void OnPropertyChanged(
- AvaloniaProperty property,
- Optional oldValue,
- BindingValue newValue,
- BindingPriority priority)
+ protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
- base.OnPropertyChanged(property, oldValue, newValue, priority);
+ base.OnPropertyChanged(change);
- if (property == PositionProperty)
+ if (change.Property == PositionProperty)
{
- UpdatePseudoClasses(newValue.GetValueOrDefault());
+ UpdatePseudoClasses(change.NewValue.GetValueOrDefault());
}
}
diff --git a/src/Avalonia.Controls/Presenters/TextPresenter.cs b/src/Avalonia.Controls/Presenters/TextPresenter.cs
index 9cbde72f7f..09f86f462c 100644
--- a/src/Avalonia.Controls/Presenters/TextPresenter.cs
+++ b/src/Avalonia.Controls/Presenters/TextPresenter.cs
@@ -75,6 +75,9 @@ namespace Avalonia.Controls.Presenters
static TextPresenter()
{
AffectsRender(SelectionBrushProperty);
+ AffectsMeasure(TextProperty, PasswordCharProperty,
+ TextAlignmentProperty, TextWrappingProperty, TextBlock.FontSizeProperty,
+ TextBlock.FontStyleProperty, TextBlock.FontWeightProperty, TextBlock.FontFamilyProperty);
Observable.Merge(TextProperty.Changed, TextBlock.ForegroundProperty.Changed,
TextAlignmentProperty.Changed, TextWrappingProperty.Changed,
@@ -284,8 +287,6 @@ namespace Avalonia.Controls.Presenters
protected void InvalidateFormattedText()
{
_formattedText = null;
-
- InvalidateMeasure();
}
///
@@ -301,13 +302,15 @@ namespace Avalonia.Controls.Presenters
context.FillRectangle(background, new Rect(Bounds.Size));
}
- FormattedText.Constraint = Bounds.Size;
-
context.DrawText(Foreground, new Point(), FormattedText);
}
public override void Render(DrawingContext context)
{
+ FormattedText.Constraint = Bounds.Size;
+
+ _constraint = Bounds.Size;
+
var selectionStart = SelectionStart;
var selectionEnd = SelectionEnd;
@@ -316,10 +319,6 @@ namespace Avalonia.Controls.Presenters
var start = Math.Min(selectionStart, selectionEnd);
var length = Math.Max(selectionStart, selectionEnd) - start;
- // issue #600: set constraint before any FormattedText manipulation
- // see base.Render(...) implementation
- FormattedText.Constraint = _constraint;
-
var rects = FormattedText.HitTestTextRange(start, length);
foreach (var rect in rects)
diff --git a/src/Avalonia.Controls/Primitives/ScrollBar.cs b/src/Avalonia.Controls/Primitives/ScrollBar.cs
index 2e6292b4b4..f6186a29a9 100644
--- a/src/Avalonia.Controls/Primitives/ScrollBar.cs
+++ b/src/Avalonia.Controls/Primitives/ScrollBar.cs
@@ -123,24 +123,20 @@ namespace Avalonia.Controls.Primitives
}
}
- protected override void OnPropertyChanged(
- AvaloniaProperty property,
- Optional oldValue,
- BindingValue newValue,
- BindingPriority priority)
+ protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
- base.OnPropertyChanged(property, oldValue, newValue, priority);
+ base.OnPropertyChanged(change);
- if (property == OrientationProperty)
+ if (change.Property == OrientationProperty)
{
- UpdatePseudoClasses(newValue.GetValueOrDefault());
+ UpdatePseudoClasses(change.NewValue.GetValueOrDefault());
}
else
{
- if (property == MinimumProperty ||
- property == MaximumProperty ||
- property == ViewportSizeProperty ||
- property == VisibilityProperty)
+ if (change.Property == MinimumProperty ||
+ change.Property == MaximumProperty ||
+ change.Property == ViewportSizeProperty ||
+ change.Property == VisibilityProperty)
{
UpdateIsVisible();
}
diff --git a/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs b/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs
index 8fc1a55e68..c915dc70b6 100644
--- a/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs
+++ b/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs
@@ -455,13 +455,13 @@ namespace Avalonia.Controls.Primitives
InternalEndInit();
}
- protected override void OnPropertyChanged(AvaloniaProperty property, Optional oldValue, BindingValue newValue, BindingPriority priority)
+ protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
- base.OnPropertyChanged(property, oldValue, newValue, priority);
+ base.OnPropertyChanged(change);
- if (property == SelectionModeProperty)
+ if (change.Property == SelectionModeProperty)
{
- var mode = newValue.GetValueOrDefault();
+ var mode = change.NewValue.GetValueOrDefault();
Selection.SingleSelect = !mode.HasFlagCustom(SelectionMode.Multiple);
Selection.AutoSelect = mode.HasFlagCustom(SelectionMode.AlwaysSelected);
}
diff --git a/src/Avalonia.Controls/Primitives/Track.cs b/src/Avalonia.Controls/Primitives/Track.cs
index 1e02d70fff..e104a8a664 100644
--- a/src/Avalonia.Controls/Primitives/Track.cs
+++ b/src/Avalonia.Controls/Primitives/Track.cs
@@ -280,17 +280,13 @@ namespace Avalonia.Controls.Primitives
return arrangeSize;
}
- protected override void OnPropertyChanged(
- AvaloniaProperty property,
- Optional oldValue,
- BindingValue newValue,
- BindingPriority priority)
+ protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
- base.OnPropertyChanged(property, oldValue, newValue, priority);
+ base.OnPropertyChanged(change);
- if (property == OrientationProperty)
+ if (change.Property == OrientationProperty)
{
- UpdatePseudoClasses(newValue.GetValueOrDefault());
+ UpdatePseudoClasses(change.NewValue.GetValueOrDefault());
}
}
diff --git a/src/Avalonia.Controls/ProgressBar.cs b/src/Avalonia.Controls/ProgressBar.cs
index 9225625bf5..c7356f2b4d 100644
--- a/src/Avalonia.Controls/ProgressBar.cs
+++ b/src/Avalonia.Controls/ProgressBar.cs
@@ -83,21 +83,17 @@ namespace Avalonia.Controls
return base.ArrangeOverride(finalSize);
}
- protected override void OnPropertyChanged(
- AvaloniaProperty property,
- Optional oldValue,
- BindingValue newValue,
- BindingPriority priority)
+ protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
- base.OnPropertyChanged(property, oldValue, newValue, priority);
+ base.OnPropertyChanged(change);
- if (property == IsIndeterminateProperty)
+ if (change.Property == IsIndeterminateProperty)
{
- UpdatePseudoClasses(newValue.GetValueOrDefault(), null);
+ UpdatePseudoClasses(change.NewValue.GetValueOrDefault(), null);
}
- else if (property == OrientationProperty)
+ else if (change.Property == OrientationProperty)
{
- UpdatePseudoClasses(null, newValue.GetValueOrDefault());
+ UpdatePseudoClasses(null, change.NewValue.GetValueOrDefault());
}
}
diff --git a/src/Avalonia.Controls/Repeater/ItemsRepeater.cs b/src/Avalonia.Controls/Repeater/ItemsRepeater.cs
index 12fba12c8c..069da6e9ac 100644
--- a/src/Avalonia.Controls/Repeater/ItemsRepeater.cs
+++ b/src/Avalonia.Controls/Repeater/ItemsRepeater.cs
@@ -376,12 +376,12 @@ namespace Avalonia.Controls
_viewportManager.ResetScrollers();
}
- protected override void OnPropertyChanged(AvaloniaProperty property, Optional oldValue, BindingValue newValue, BindingPriority priority)
+ protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
- if (property == ItemsProperty)
+ if (change.Property == ItemsProperty)
{
- var oldEnumerable = oldValue.GetValueOrDefault();
- var newEnumerable = newValue.GetValueOrDefault();
+ var oldEnumerable = change.OldValue.GetValueOrDefault();
+ var newEnumerable = change.NewValue.GetValueOrDefault();
if (oldEnumerable != newEnumerable)
{
@@ -394,24 +394,28 @@ namespace Avalonia.Controls
OnDataSourcePropertyChanged(ItemsSourceView, newDataSource);
}
}
- else if (property == ItemTemplateProperty)
+ else if (change.Property == ItemTemplateProperty)
{
- OnItemTemplateChanged(oldValue.GetValueOrDefault(), newValue.GetValueOrDefault());
+ OnItemTemplateChanged(
+ change.OldValue.GetValueOrDefault(),
+ change.NewValue.GetValueOrDefault());
}
- else if (property == LayoutProperty)
+ else if (change.Property == LayoutProperty)
{
- OnLayoutChanged(oldValue.GetValueOrDefault(), newValue.GetValueOrDefault());
+ OnLayoutChanged(
+ change.OldValue.GetValueOrDefault(),
+ change.NewValue.GetValueOrDefault());
}
- else if (property == HorizontalCacheLengthProperty)
+ else if (change.Property == HorizontalCacheLengthProperty)
{
- _viewportManager.HorizontalCacheLength = newValue.GetValueOrDefault();
+ _viewportManager.HorizontalCacheLength = change.NewValue.GetValueOrDefault();
}
- else if (property == VerticalCacheLengthProperty)
+ else if (change.Property == VerticalCacheLengthProperty)
{
- _viewportManager.VerticalCacheLength = newValue.GetValueOrDefault();
+ _viewportManager.VerticalCacheLength = change.NewValue.GetValueOrDefault();
}
- base.OnPropertyChanged(property, oldValue, newValue, priority);
+ base.OnPropertyChanged(change);
}
internal IControl GetElementImpl(int index, bool forceCreate, bool supressAutoRecycle)
diff --git a/src/Avalonia.Controls/Slider.cs b/src/Avalonia.Controls/Slider.cs
index f243372926..e92c8faf20 100644
--- a/src/Avalonia.Controls/Slider.cs
+++ b/src/Avalonia.Controls/Slider.cs
@@ -134,17 +134,13 @@ namespace Avalonia.Controls
}
}
- protected override void OnPropertyChanged(
- AvaloniaProperty property,
- Optional oldValue,
- BindingValue newValue,
- BindingPriority priority)
+ protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
- base.OnPropertyChanged(property, oldValue, newValue, priority);
+ base.OnPropertyChanged(change);
- if (property == OrientationProperty)
+ if (change.Property == OrientationProperty)
{
- UpdatePseudoClasses(newValue.GetValueOrDefault());
+ UpdatePseudoClasses(change.NewValue.GetValueOrDefault());
}
}
diff --git a/src/Avalonia.Controls/TreeView.cs b/src/Avalonia.Controls/TreeView.cs
index a55274afb3..95e7437838 100644
--- a/src/Avalonia.Controls/TreeView.cs
+++ b/src/Avalonia.Controls/TreeView.cs
@@ -486,13 +486,13 @@ namespace Avalonia.Controls
}
}
- protected override void OnPropertyChanged(AvaloniaProperty property, Optional oldValue, BindingValue newValue, BindingPriority priority)
+ protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
- base.OnPropertyChanged(property, oldValue, newValue, priority);
+ base.OnPropertyChanged(change);
- if (property == SelectionModeProperty)
+ if (change.Property == SelectionModeProperty)
{
- var mode = newValue.GetValueOrDefault();
+ var mode = change.NewValue.GetValueOrDefault();
Selection.SingleSelect = !mode.HasFlagCustom(SelectionMode.Multiple);
Selection.AutoSelect = mode.HasFlagCustom(SelectionMode.AlwaysSelected);
}
diff --git a/src/Avalonia.Controls/Window.cs b/src/Avalonia.Controls/Window.cs
index 194ebeb999..474d845905 100644
--- a/src/Avalonia.Controls/Window.cs
+++ b/src/Avalonia.Controls/Window.cs
@@ -751,19 +751,15 @@ namespace Avalonia.Controls
///
protected virtual void OnClosing(CancelEventArgs e) => Closing?.Invoke(this, e);
- protected override void OnPropertyChanged(
- AvaloniaProperty property,
- Optional oldValue,
- BindingValue newValue,
- BindingPriority priority)
+ protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
- if (property == SystemDecorationsProperty)
+ if (change.Property == SystemDecorationsProperty)
{
- var typedNewValue = newValue.GetValueOrDefault();
+ var typedNewValue = change.NewValue.GetValueOrDefault();
PlatformImpl?.SetSystemDecorations(typedNewValue);
- var o = oldValue.GetValueOrDefault() == SystemDecorations.Full;
+ var o = change.OldValue.GetValueOrDefault() == SystemDecorations.Full;
var n = typedNewValue == SystemDecorations.Full;
if (o != n)
diff --git a/src/Avalonia.Input/InputElement.cs b/src/Avalonia.Input/InputElement.cs
index 20c775f965..407b28b665 100644
--- a/src/Avalonia.Input/InputElement.cs
+++ b/src/Avalonia.Input/InputElement.cs
@@ -526,17 +526,17 @@ namespace Avalonia.Input
{
}
- protected override void OnPropertyChanged(AvaloniaProperty