diff --git a/src/Avalonia.Base/AvaloniaObject.cs b/src/Avalonia.Base/AvaloniaObject.cs
index b0db89f7ea..fd4f495edb 100644
--- a/src/Avalonia.Base/AvaloniaObject.cs
+++ b/src/Avalonia.Base/AvaloniaObject.cs
@@ -261,25 +261,12 @@ namespace Avalonia
}
else
{
- object result = AvaloniaProperty.UnsetValue;
- PriorityValue value;
-
if (!AvaloniaPropertyRegistry.Instance.IsRegistered(this, property))
{
ThrowNotRegistered(property);
}
- if (_values.TryGetValue(property, out value))
- {
- result = value.Value;
- }
-
- if (result == AvaloniaProperty.UnsetValue)
- {
- result = GetDefaultValue(property);
- }
-
- return result;
+ return GetValueInternal(property);
}
}
@@ -767,7 +754,7 @@ namespace Avalonia
{
if (property.Inherits && _inheritanceParent != null)
{
- return _inheritanceParent.GetValue(property);
+ return (_inheritanceParent as AvaloniaObject).GetValueInternal(property);
}
else
{
@@ -775,6 +762,32 @@ namespace Avalonia
}
}
+ ///
+ /// Gets a value
+ /// without check for registered as this can slow getting the value
+ /// this method is intended for internal usage in AvaloniaObject only
+ /// it's called only after check the property is registered
+ ///
+ /// The property.
+ /// The value.
+ private object GetValueInternal(AvaloniaProperty property)
+ {
+ object result = AvaloniaProperty.UnsetValue;
+ PriorityValue value;
+
+ if (_values.TryGetValue(property, out value))
+ {
+ result = value.Value;
+ }
+
+ if (result == AvaloniaProperty.UnsetValue)
+ {
+ result = GetDefaultValue(property);
+ }
+
+ return result;
+ }
+
///
/// Given a returns a registered avalonia property that is
/// equal or throws if not found.
@@ -849,4 +862,4 @@ namespace Avalonia
throw new ArgumentException($"Property '{p.Name} not registered on '{this.GetType()}");
}
}
-}
+}
\ No newline at end of file
diff --git a/src/Avalonia.Base/AvaloniaProperty.cs b/src/Avalonia.Base/AvaloniaProperty.cs
index b815c90295..0f5500b116 100644
--- a/src/Avalonia.Base/AvaloniaProperty.cs
+++ b/src/Avalonia.Base/AvaloniaProperty.cs
@@ -26,6 +26,7 @@ namespace Avalonia
private readonly Subject _changed;
private readonly PropertyMetadata _defaultMetadata;
private readonly Dictionary _metadata;
+ private readonly Dictionary _metadataCache = new Dictionary();
///
/// Initializes a new instance of the class.
@@ -73,8 +74,8 @@ namespace Avalonia
/// The new owner type.
/// Optional overridden metadata.
protected AvaloniaProperty(
- AvaloniaProperty source,
- Type ownerType,
+ AvaloniaProperty source,
+ Type ownerType,
PropertyMetadata metadata)
{
Contract.Requires(source != null);
@@ -163,11 +164,11 @@ namespace Avalonia
/// object.
///
///
- /// When a property changes, change notifications are sent to all property subscribers;
- /// for example via the observable and and the
+ /// When a property changes, change notifications are sent to all property subscribers;
+ /// for example via the observable and and the
/// event. If this callback is set for a property,
/// then it will be called before and after these notifications take place. The bool argument
- /// will be true before the property change notifications are sent and false afterwards. This
+ /// will be true before the property change notifications are sent and false afterwards. This
/// callback is intended to support Control.IsDataContextChanging.
///
public Action Notifying { get; }
@@ -273,8 +274,8 @@ namespace Avalonia
defaultBindingMode: defaultBindingMode);
var result = new StyledProperty(
- name,
- typeof(TOwner),
+ name,
+ typeof(TOwner),
metadata,
inherits,
notifying);
@@ -423,24 +424,9 @@ namespace Avalonia
///
public PropertyMetadata GetMetadata() where T : IAvaloniaObject
{
- var type = typeof(T);
-
- while (type != null)
- {
- PropertyMetadata result;
-
- if (_metadata.TryGetValue(type, out result))
- {
- return result;
- }
-
- type = type.GetTypeInfo().BaseType;
- }
-
- return _defaultMetadata;
+ return GetMetadata(typeof(T));
}
-
///
/// Gets the property metadata for the specified type.
///
@@ -448,22 +434,33 @@ namespace Avalonia
///
/// The property metadata.
///
+ ///
public PropertyMetadata GetMetadata(Type type)
{
Contract.Requires(type != null);
- while (type != null)
+ PropertyMetadata result;
+ Type currentType = type;
+
+ if (_metadataCache.TryGetValue(type, out result))
{
- PropertyMetadata result;
+ return result;
+ }
- if (_metadata.TryGetValue(type, out result))
+ while (currentType != null)
+ {
+ if (_metadata.TryGetValue(currentType, out result))
{
+ _metadataCache[type] = result;
+
return result;
}
- type = type.GetTypeInfo().BaseType;
+ currentType = currentType.GetTypeInfo().BaseType;
}
+ _metadataCache[type] = _defaultMetadata;
+
return _defaultMetadata;
}
@@ -523,6 +520,7 @@ namespace Avalonia
var baseMetadata = GetMetadata(type);
metadata.Merge(baseMetadata, this);
_metadata.Add(type, metadata);
+ _metadataCache.Clear();
}
[DebuggerHidden]
@@ -551,4 +549,4 @@ namespace Avalonia
public override string ToString() => "(unset)";
}
}
-}
+}
\ No newline at end of file
diff --git a/src/Avalonia.Base/AvaloniaPropertyRegistry.cs b/src/Avalonia.Base/AvaloniaPropertyRegistry.cs
index eaff31fbac..a1d6db64df 100644
--- a/src/Avalonia.Base/AvaloniaPropertyRegistry.cs
+++ b/src/Avalonia.Base/AvaloniaPropertyRegistry.cs
@@ -20,6 +20,12 @@ namespace Avalonia
private readonly Dictionary> _registered =
new Dictionary>();
+ ///
+ /// The registered properties by type cached values to increase performance.
+ ///
+ private readonly Dictionary> _registeredCache =
+ new Dictionary>();
+
///
/// The registered attached properties by owner type.
///
@@ -103,21 +109,38 @@ namespace Avalonia
///
public AvaloniaProperty FindRegistered(Type type, AvaloniaProperty property)
{
- while (type != null)
+ Type currentType = type;
+ Dictionary cache;
+ AvaloniaProperty result;
+
+ if (_registeredCache.TryGetValue(type, out cache))
+ {
+ if (cache.TryGetValue(property.Id, out result))
+ {
+ return result;
+ }
+ }
+
+ while (currentType != null)
{
Dictionary inner;
- if (_registered.TryGetValue(type, out inner))
+ if (_registered.TryGetValue(currentType, out inner))
{
- AvaloniaProperty result;
-
if (inner.TryGetValue(property.Id, out result))
{
+ if (cache == null)
+ {
+ _registeredCache[type] = cache = new Dictionary();
+ }
+
+ cache[property.Id] = result;
+
return result;
}
}
- type = type.GetTypeInfo().BaseType;
+ currentType = currentType.GetTypeInfo().BaseType;
}
return null;
@@ -130,7 +153,7 @@ namespace Avalonia
/// The property.
/// The registered property or null if not found.
///
- /// Calling AddOwner on a AvaloniaProperty creates a new AvaloniaProperty that is a
+ /// Calling AddOwner on a AvaloniaProperty creates a new AvaloniaProperty that is a
/// different object but is equal according to .
///
public AvaloniaProperty FindRegistered(object o, AvaloniaProperty property)
@@ -143,7 +166,7 @@ namespace Avalonia
///
/// The type.
///
- /// The property name. If an attached property it should be in the form
+ /// The property name. If an attached property it should be in the form
/// "OwnerType.PropertyName".
///
///
@@ -183,13 +206,12 @@ namespace Avalonia
return results.FirstOrDefault(x => x.Name == propertyName);
}
-
///
/// Finds a registered property on an object by name.
///
/// The object.
///
- /// The property name. If an attached property it should be in the form
+ /// The property name. If an attached property it should be in the form
/// "OwnerType.PropertyName".
///
///
@@ -276,6 +298,8 @@ namespace Avalonia
inner.Add(property.Id, property);
}
}
+
+ _registeredCache.Clear();
}
}
-}
+}
\ No newline at end of file