Browse Source

Merge pull request #2127 from AvaloniaUI/perf/cache-ao-initialization

[Perf] Cache AvaloniaObject initialization notifications.
pull/2321/head
Steven Kirk 7 years ago
committed by GitHub
parent
commit
fe74dfe538
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 46
      src/Avalonia.Base/AvaloniaObject.cs
  2. 55
      src/Avalonia.Base/AvaloniaPropertyRegistry.cs

46
src/Avalonia.Base/AvaloniaObject.cs

@ -22,27 +22,10 @@ namespace Avalonia
/// </remarks> /// </remarks>
public class AvaloniaObject : IAvaloniaObject, IAvaloniaObjectDebug, INotifyPropertyChanged public class AvaloniaObject : IAvaloniaObject, IAvaloniaObjectDebug, INotifyPropertyChanged
{ {
/// <summary>
/// The parent object that inherited values are inherited from.
/// </summary>
private IAvaloniaObject _inheritanceParent; 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; private List<DirectBindingSubscription> _directBindings;
/// <summary>
/// Event handler for <see cref="INotifyPropertyChanged"/> implementation.
/// </summary>
private PropertyChangedEventHandler _inpcChanged; private PropertyChangedEventHandler _inpcChanged;
/// <summary>
/// Event handler for <see cref="PropertyChanged"/> implementation.
/// </summary>
private EventHandler<AvaloniaPropertyChangedEventArgs> _propertyChanged; private EventHandler<AvaloniaPropertyChangedEventArgs> _propertyChanged;
private ValueStore _values; private ValueStore _values;
private ValueStore Values => _values ?? (_values = new ValueStore(this)); private ValueStore Values => _values ?? (_values = new ValueStore(this));
@ -52,32 +35,7 @@ namespace Avalonia
public AvaloniaObject() public AvaloniaObject()
{ {
VerifyAccess(); VerifyAccess();
AvaloniaPropertyRegistry.Instance.NotifyInitialized(this);
void Notify(AvaloniaProperty property)
{
object value = property.IsDirect ?
((IDirectPropertyAccessor)property).GetValue(this) :
((IStyledPropertyAccessor)property).GetDefaultValue(GetType());
var e = new AvaloniaPropertyChangedEventArgs(
this,
property,
AvaloniaProperty.UnsetValue,
value,
BindingPriority.Unset);
property.NotifyInitialized(e);
}
foreach (var property in AvaloniaPropertyRegistry.Instance.GetRegistered(this))
{
Notify(property);
}
foreach (var property in AvaloniaPropertyRegistry.Instance.GetRegisteredAttached(this.GetType()))
{
Notify(property);
}
} }
/// <summary> /// <summary>
@ -628,7 +586,7 @@ namespace Avalonia
/// </summary> /// </summary>
/// <param name="property">The property.</param> /// <param name="property">The property.</param>
/// <returns>The default value.</returns> /// <returns>The default value.</returns>
internal object GetDefaultValue(AvaloniaProperty property) private object GetDefaultValue(AvaloniaProperty property)
{ {
if (property.Inherits && InheritanceParent is AvaloniaObject aobj) if (property.Inherits && InheritanceParent is AvaloniaObject aobj)
return aobj.GetValue(property); return aobj.GetValue(property);

55
src/Avalonia.Base/AvaloniaPropertyRegistry.cs

@ -5,6 +5,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using Avalonia.Data;
namespace Avalonia namespace Avalonia
{ {
@ -23,6 +24,8 @@ namespace Avalonia
new Dictionary<Type, List<AvaloniaProperty>>(); new Dictionary<Type, List<AvaloniaProperty>>();
private readonly Dictionary<Type, List<AvaloniaProperty>> _attachedCache = private readonly Dictionary<Type, List<AvaloniaProperty>> _attachedCache =
new Dictionary<Type, List<AvaloniaProperty>>(); new Dictionary<Type, List<AvaloniaProperty>>();
private readonly Dictionary<Type, List<KeyValuePair<AvaloniaProperty, object>>> _initializedCache =
new Dictionary<Type, List<KeyValuePair<AvaloniaProperty, object>>>();
/// <summary> /// <summary>
/// Gets the <see cref="AvaloniaPropertyRegistry"/> instance /// Gets the <see cref="AvaloniaPropertyRegistry"/> instance
@ -226,6 +229,7 @@ namespace Avalonia
} }
_registeredCache.Clear(); _registeredCache.Clear();
_initializedCache.Clear();
} }
/// <summary> /// <summary>
@ -261,6 +265,57 @@ namespace Avalonia
} }
_attachedCache.Clear(); _attachedCache.Clear();
_initializedCache.Clear();
}
internal void NotifyInitialized(AvaloniaObject o)
{
Contract.Requires<ArgumentNullException>(o != null);
var type = o.GetType();
void Notify(AvaloniaProperty property, object value)
{
var e = new AvaloniaPropertyChangedEventArgs(
o,
property,
AvaloniaProperty.UnsetValue,
value,
BindingPriority.Unset);
property.NotifyInitialized(e);
}
if (!_initializedCache.TryGetValue(type, out var items))
{
var build = new Dictionary<AvaloniaProperty, object>();
foreach (var property in GetRegistered(type))
{
var value = !property.IsDirect ?
((IStyledPropertyAccessor)property).GetDefaultValue(type) :
null;
build.Add(property, value);
}
foreach (var property in GetRegisteredAttached(type))
{
if (!build.ContainsKey(property))
{
var value = ((IStyledPropertyAccessor)property).GetDefaultValue(type);
build.Add(property, value);
}
}
items = build.ToList();
_initializedCache.Add(type, items);
}
foreach (var i in items)
{
var value = i.Key.IsDirect ? o.GetValue(i.Key) : i.Value;
Notify(i.Key, value);
}
} }
} }
} }

Loading…
Cancel
Save