Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
139 changes: 33 additions & 106 deletions src/Avalonia.Base/AvaloniaObject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,6 @@ public class AvaloniaObject : IAvaloniaObject, IAvaloniaObjectDebug, INotifyProp
/// </summary>
private IAvaloniaObject _inheritanceParent;

/// <summary>
/// The set values/bindings on this object.
/// </summary>
private readonly Dictionary<AvaloniaProperty, PriorityValue> _values =
new Dictionary<AvaloniaProperty, PriorityValue>();

/// <summary>
/// Maintains a list of direct property binding subscriptions so that the binding source
/// doesn't get collected.
Expand All @@ -52,6 +46,7 @@ public class AvaloniaObject : IAvaloniaObject, IAvaloniaObjectDebug, INotifyProp
private EventHandler<AvaloniaPropertyChangedEventArgs> _propertyChanged;

private DeferredSetter<AvaloniaProperty, object> _directDeferredSetter;
private ValueStore _values;

/// <summary>
/// Delayed setter helper for direct properties. Used to fix #855.
Expand Down Expand Up @@ -228,9 +223,20 @@ public object GetValue(AvaloniaProperty property)
{
return ((IDirectPropertyAccessor)GetRegistered(property)).GetValue(this);
}
else if (_values != null)
{
var result = _values.GetValue(property);

if (result == AvaloniaProperty.UnsetValue)
{
result = GetDefaultValue(property);
}

return result;
}
else
{
return GetValueInternal(property);
return GetDefaultValue(property);
}
}

Expand All @@ -257,7 +263,7 @@ public bool IsAnimating(AvaloniaProperty property)
Contract.Requires<ArgumentNullException>(property != null);
VerifyAccess();

return _values.TryGetValue(property, out PriorityValue value) ? value.IsAnimating : false;
return _values?.IsAnimating(property) ?? false;
}

/// <summary>
Expand All @@ -274,14 +280,7 @@ public bool IsSet(AvaloniaProperty property)
Contract.Requires<ArgumentNullException>(property != null);
VerifyAccess();

PriorityValue value;

if (_values.TryGetValue(property, out value))
{
return value.Value != AvaloniaProperty.UnsetValue;
}

return false;
return _values?.IsSet(property) ?? false;
}

/// <summary>
Expand Down Expand Up @@ -369,14 +368,6 @@ public IDisposable Bind(
}
else
{
PriorityValue v;

if (!_values.TryGetValue(property, out v))
{
v = CreatePriorityValue(property);
_values.Add(property, v);
}

Logger.Verbose(
LogArea.Property,
this,
Expand All @@ -385,7 +376,12 @@ public IDisposable Bind(
description,
priority);

return v.Add(source, (int)priority);
if (_values == null)
{
_values = new ValueStore(this);
}

return _values.AddBinding(property, source, priority);
}
}

Expand Down Expand Up @@ -416,20 +412,12 @@ public IDisposable Bind<T>(
public void Revalidate(AvaloniaProperty property)
{
VerifyAccess();
PriorityValue value;

if (_values.TryGetValue(property, out value))
{
value.Revalidate();
}
_values?.Revalidate(property);
}

/// <inheritdoc/>
void IPriorityValueOwner.Changed(PriorityValue sender, object oldValue, object newValue)
void IPriorityValueOwner.Changed(AvaloniaProperty property, int priority, object oldValue, object newValue)
{
var property = sender.Property;
var priority = (BindingPriority)sender.ValuePriority;

oldValue = (oldValue == AvaloniaProperty.UnsetValue) ?
GetDefaultValue(property) :
oldValue;
Expand All @@ -439,7 +427,7 @@ void IPriorityValueOwner.Changed(PriorityValue sender, object oldValue, object n

if (!Equals(oldValue, newValue))
{
RaisePropertyChanged(property, oldValue, newValue, priority);
RaisePropertyChanged(property, oldValue, newValue, (BindingPriority)priority);

Logger.Verbose(
LogArea.Property,
Expand All @@ -448,14 +436,14 @@ void IPriorityValueOwner.Changed(PriorityValue sender, object oldValue, object n
property,
oldValue,
newValue,
priority);
(BindingPriority)priority);
}
}

/// <inheritdoc/>
void IPriorityValueOwner.BindingNotificationReceived(PriorityValue sender, BindingNotification notification)
void IPriorityValueOwner.BindingNotificationReceived(AvaloniaProperty property, BindingNotification notification)
{
UpdateDataValidation(sender.Property, notification);
UpdateDataValidation(property, notification);
}

/// <inheritdoc/>
Expand All @@ -468,10 +456,7 @@ Delegate[] IAvaloniaObjectDebug.GetPropertyChangedSubscribers()
/// Gets all priority values set on the object.
/// </summary>
/// <returns>A collection of property/value tuples.</returns>
internal IDictionary<AvaloniaProperty, PriorityValue> GetSetValues()
{
return _values;
}
internal IDictionary<AvaloniaProperty, PriorityValue> GetSetValues() => _values?.GetSetValues();

/// <summary>
/// Forces revalidation of properties when a property value changes.
Expand Down Expand Up @@ -660,68 +645,18 @@ private static object CastOrDefault(object value, Type type)
}
}

/// <summary>
/// Creates a <see cref="PriorityValue"/> for a <see cref="AvaloniaProperty"/>.
/// </summary>
/// <param name="property">The property.</param>
/// <returns>The <see cref="PriorityValue"/>.</returns>
private PriorityValue CreatePriorityValue(AvaloniaProperty property)
{
var validate = ((IStyledPropertyAccessor)property).GetValidationFunc(GetType());
Func<object, object> validate2 = null;

if (validate != null)
{
validate2 = v => validate(this, v);
}

PriorityValue result = new PriorityValue(
this,
property,
property.PropertyType,
validate2);

return result;
}

/// <summary>
/// Gets the default value for a property.
/// </summary>
/// <param name="property">The property.</param>
/// <returns>The default value.</returns>
private object GetDefaultValue(AvaloniaProperty property)
internal object GetDefaultValue(AvaloniaProperty property)
{
if (property.Inherits && InheritanceParent is AvaloniaObject aobj)
return aobj.GetValueInternal(property);
return aobj.GetValue(property);
return ((IStyledPropertyAccessor) property).GetDefaultValue(GetType());
}

/// <summary>
/// Gets a <see cref="AvaloniaProperty"/> 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
/// </summary>
/// <param name="property">The property.</param>
/// <returns>The value.</returns>
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;
}

/// <summary>
/// Sets the value of a direct property.
/// </summary>
Expand Down Expand Up @@ -802,21 +737,13 @@ private void SetStyledValue(AvaloniaProperty property, object value, BindingPrio
originalValue?.GetType().FullName ?? "(null)"));
}

PriorityValue v;

if (!_values.TryGetValue(property, out v))
if (_values == null)
{
if (value == AvaloniaProperty.UnsetValue)
{
return;
}

v = CreatePriorityValue(property);
_values.Add(property, v);
_values = new ValueStore(this);
}

LogPropertySet(property, value, priority);
v.SetValue(value, (int)priority);
_values.AddValue(property, value, (int)priority);
}

/// <summary>
Expand Down
9 changes: 5 additions & 4 deletions src/Avalonia.Base/IPriorityValueOwner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,19 @@ internal interface IPriorityValueOwner
/// <summary>
/// Called when a <see cref="PriorityValue"/>'s value changes.
/// </summary>
/// <param name="sender">The source of the change.</param>
/// <param name="property">The the property that has changed.</param>
/// <param name="priority">The priority of the value.</param>
/// <param name="oldValue">The old value.</param>
/// <param name="newValue">The new value.</param>
void Changed(PriorityValue sender, object oldValue, object newValue);
void Changed(AvaloniaProperty property, int priority, object oldValue, object newValue);

/// <summary>
/// Called when a <see cref="BindingNotification"/> is received by a
/// <see cref="PriorityValue"/>.
/// </summary>
/// <param name="sender">The source of the change.</param>
/// <param name="property">The the property that has changed.</param>
/// <param name="notification">The notification.</param>
void BindingNotificationReceived(PriorityValue sender, BindingNotification notification);
void BindingNotificationReceived(AvaloniaProperty property, BindingNotification notification);

/// <summary>
/// Ensures that the current thread is the UI thread.
Expand Down
4 changes: 2 additions & 2 deletions src/Avalonia.Base/PriorityValue.cs
Original file line number Diff line number Diff line change
Expand Up @@ -281,12 +281,12 @@ private bool UpdateCore(

if (notification == null || notification.HasValue)
{
notify(() => Owner?.Changed(this, old, Value));
notify(() => Owner?.Changed(Property, ValuePriority, old, Value));
}

if (notification != null)
{
Owner?.BindingNotificationReceived(this, notification);
Owner?.BindingNotificationReceived(Property, notification);
}
}
else
Expand Down
Loading