Browse Source

Fix order of inherited property changed events.

Previously `PropertyChanged` was raised on the child before the parent because the inherited value change was being notified by listening to the parent `PropertyChanged` event, and this event handler was added first.

Added an `InheritablePropertyChanged` event which will be called only after all other property changed events have been raised and only for inheritable properties.
pull/2264/head
Steven Kirk 7 years ago
parent
commit
f75f85af2b
  1. 37
      src/Avalonia.Base/AvaloniaObject.cs
  2. 7
      src/Avalonia.Base/IAvaloniaObject.cs
  3. 1
      tests/Avalonia.Styling.UnitTests/SelectorTests_Child.cs
  4. 1
      tests/Avalonia.Styling.UnitTests/SelectorTests_Descendent.cs
  5. 1
      tests/Avalonia.Styling.UnitTests/TestControlBase.cs
  6. 1
      tests/Avalonia.Styling.UnitTests/TestTemplatedControl.cs

37
src/Avalonia.Base/AvaloniaObject.cs

@ -22,27 +22,11 @@ namespace Avalonia
/// </remarks>
public class AvaloniaObject : IAvaloniaObject, IAvaloniaObjectDebug, INotifyPropertyChanged
{
/// <summary>
/// The parent object that inherited values are inherited from.
/// </summary>
private IAvaloniaObject _inheritanceParent;
/// <summary>
/// Maintains a list of direct property binding subscriptions so that the binding source
/// doesn't get collected.
/// </summary>
private List<DirectBindingSubscription> _directBindings;
/// <summary>
/// Event handler for <see cref="INotifyPropertyChanged"/> implementation.
/// </summary>
private PropertyChangedEventHandler _inpcChanged;
/// <summary>
/// Event handler for <see cref="PropertyChanged"/> implementation.
/// </summary>
private EventHandler<AvaloniaPropertyChangedEventArgs> _propertyChanged;
private EventHandler<AvaloniaPropertyChangedEventArgs> _inheritablePropertyChanged;
private ValueStore _values;
private ValueStore Values => _values ?? (_values = new ValueStore(this));
@ -98,6 +82,15 @@ namespace Avalonia
remove { _inpcChanged -= value; }
}
/// <summary>
/// Raised when an inheritable <see cref="AvaloniaProperty"/> value changes on this object.
/// </summary>
event EventHandler<AvaloniaPropertyChangedEventArgs> IAvaloniaObject.InheritablePropertyChanged
{
add { _inheritablePropertyChanged += value; }
remove { _inheritablePropertyChanged -= value; }
}
/// <summary>
/// Gets or sets the parent object that inherited <see cref="AvaloniaProperty"/> values
/// are inherited from.
@ -118,8 +111,9 @@ namespace Avalonia
{
if (_inheritanceParent != null)
{
_inheritanceParent.PropertyChanged -= ParentPropertyChanged;
_inheritanceParent.InheritablePropertyChanged -= ParentPropertyChanged;
}
var properties = AvaloniaPropertyRegistry.Instance.GetRegistered(this)
.Concat(AvaloniaPropertyRegistry.Instance.GetRegisteredAttached(this.GetType()));
var inherited = (from property in properties
@ -144,7 +138,7 @@ namespace Avalonia
if (_inheritanceParent != null)
{
_inheritanceParent.PropertyChanged += ParentPropertyChanged;
_inheritanceParent.InheritablePropertyChanged += ParentPropertyChanged;
}
}
}
@ -509,6 +503,11 @@ namespace Avalonia
PropertyChangedEventArgs e2 = new PropertyChangedEventArgs(property.Name);
_inpcChanged(this, e2);
}
if (property.Inherits)
{
_inheritablePropertyChanged?.Invoke(this, e);
}
}
finally
{

7
src/Avalonia.Base/IAvaloniaObject.cs

@ -16,6 +16,11 @@ namespace Avalonia
/// </summary>
event EventHandler<AvaloniaPropertyChangedEventArgs> PropertyChanged;
/// <summary>
/// Raised when an inheritable <see cref="AvaloniaProperty"/> value changes on this object.
/// </summary>
event EventHandler<AvaloniaPropertyChangedEventArgs> InheritablePropertyChanged;
/// <summary>
/// Gets a <see cref="AvaloniaProperty"/> value.
/// </summary>
@ -97,4 +102,4 @@ namespace Avalonia
IObservable<T> source,
BindingPriority priority = BindingPriority.LocalValue);
}
}
}

1
tests/Avalonia.Styling.UnitTests/SelectorTests_Child.cs

@ -89,6 +89,7 @@ namespace Avalonia.Styling.UnitTests
}
public event EventHandler<AvaloniaPropertyChangedEventArgs> PropertyChanged;
public event EventHandler<AvaloniaPropertyChangedEventArgs> InheritablePropertyChanged;
public event EventHandler<LogicalTreeAttachmentEventArgs> AttachedToLogicalTree;
public event EventHandler<LogicalTreeAttachmentEventArgs> DetachedFromLogicalTree;

1
tests/Avalonia.Styling.UnitTests/SelectorTests_Descendent.cs

@ -119,6 +119,7 @@ namespace Avalonia.Styling.UnitTests
}
public event EventHandler<AvaloniaPropertyChangedEventArgs> PropertyChanged;
public event EventHandler<AvaloniaPropertyChangedEventArgs> InheritablePropertyChanged;
public event EventHandler<LogicalTreeAttachmentEventArgs> AttachedToLogicalTree;
public event EventHandler<LogicalTreeAttachmentEventArgs> DetachedFromLogicalTree;

1
tests/Avalonia.Styling.UnitTests/TestControlBase.cs

@ -19,6 +19,7 @@ namespace Avalonia.Styling.UnitTests
#pragma warning disable CS0067 // Event not used
public event EventHandler<AvaloniaPropertyChangedEventArgs> PropertyChanged;
public event EventHandler<AvaloniaPropertyChangedEventArgs> InheritablePropertyChanged;
#pragma warning restore CS0067
public string Name { get; set; }

1
tests/Avalonia.Styling.UnitTests/TestTemplatedControl.cs

@ -12,6 +12,7 @@ namespace Avalonia.Styling.UnitTests
public abstract class TestTemplatedControl : ITemplatedControl, IStyleable
{
public event EventHandler<AvaloniaPropertyChangedEventArgs> PropertyChanged;
public event EventHandler<AvaloniaPropertyChangedEventArgs> InheritablePropertyChanged;
public abstract Classes Classes
{

Loading…
Cancel
Save