|
|
|
@ -262,42 +262,11 @@ namespace Avalonia |
|
|
|
|
|
|
|
if (property.IsDirect) |
|
|
|
{ |
|
|
|
var accessor = (IDirectPropertyAccessor)GetRegistered(property); |
|
|
|
LogPropertySet(property, value, priority); |
|
|
|
accessor.SetValue(this, DirectUnsetToDefault(value, property)); |
|
|
|
SetDirectValue(property, value); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
PriorityValue v; |
|
|
|
var originalValue = value; |
|
|
|
|
|
|
|
if (!AvaloniaPropertyRegistry.Instance.IsRegistered(this, property)) |
|
|
|
{ |
|
|
|
ThrowNotRegistered(property); |
|
|
|
} |
|
|
|
|
|
|
|
if (!TypeUtilities.TryCast(property.PropertyType, value, out value)) |
|
|
|
{ |
|
|
|
throw new ArgumentException(string.Format( |
|
|
|
"Invalid value for Property '{0}': '{1}' ({2})", |
|
|
|
property.Name, |
|
|
|
originalValue, |
|
|
|
originalValue?.GetType().FullName ?? "(null)")); |
|
|
|
} |
|
|
|
|
|
|
|
if (!_values.TryGetValue(property, out v)) |
|
|
|
{ |
|
|
|
if (value == AvaloniaProperty.UnsetValue) |
|
|
|
{ |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
v = CreatePriorityValue(property); |
|
|
|
_values.Add(property, v); |
|
|
|
} |
|
|
|
|
|
|
|
LogPropertySet(property, value, priority); |
|
|
|
v.SetValue(value, (int)priority); |
|
|
|
SetStyledValue(property, value, priority); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@ -361,7 +330,7 @@ namespace Avalonia |
|
|
|
subscription = source |
|
|
|
.Select(x => CastOrDefault(x, property.PropertyType)) |
|
|
|
.Do(_ => { }, () => _directBindings.Remove(subscription)) |
|
|
|
.Subscribe(x => DirectBindingSet(property, x)); |
|
|
|
.Subscribe(x => SetDirectValue(property, x)); |
|
|
|
|
|
|
|
_directBindings.Add(subscription); |
|
|
|
|
|
|
|
@ -642,20 +611,60 @@ namespace Avalonia |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Sets a property value for a direct property binding.
|
|
|
|
/// Gets the default value for a property.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="property">The property.</param>
|
|
|
|
/// <returns>The default value.</returns>
|
|
|
|
private object GetDefaultValue(AvaloniaProperty property) |
|
|
|
{ |
|
|
|
if (property.Inherits && _inheritanceParent != null) |
|
|
|
{ |
|
|
|
return (_inheritanceParent as AvaloniaObject).GetValueInternal(property); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
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>
|
|
|
|
/// <param name="property">The property.</param>
|
|
|
|
/// <param name="value">The value.</param>
|
|
|
|
/// <returns></returns>
|
|
|
|
private void DirectBindingSet(AvaloniaProperty property, object value) |
|
|
|
private void SetDirectValue(AvaloniaProperty property, object value) |
|
|
|
{ |
|
|
|
var validated = property.GetMetadata(GetType()).EnableDataValidation; |
|
|
|
var metadata = property.GetMetadata(GetType()); |
|
|
|
var notification = value as BindingNotification; |
|
|
|
|
|
|
|
if (notification != null) |
|
|
|
{ |
|
|
|
value = notification.Value; |
|
|
|
|
|
|
|
if (notification.ErrorType == BindingErrorType.Error) |
|
|
|
{ |
|
|
|
Logger.Error( |
|
|
|
@ -666,73 +675,85 @@ namespace Avalonia |
|
|
|
property, |
|
|
|
ExceptionUtilities.GetMessage(notification.Error)); |
|
|
|
} |
|
|
|
|
|
|
|
if (notification.HasValue) |
|
|
|
{ |
|
|
|
value = notification.Value; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (notification?.HasValue != false) |
|
|
|
if (notification == null || notification.HasValue) |
|
|
|
{ |
|
|
|
SetValue(property, value); |
|
|
|
var accessor = (IDirectPropertyAccessor)GetRegistered(property); |
|
|
|
var finalValue = value == AvaloniaProperty.UnsetValue ? |
|
|
|
((IDirectPropertyMetadata)metadata).UnsetValue : value; |
|
|
|
|
|
|
|
LogPropertySet(property, value, BindingPriority.LocalValue); |
|
|
|
|
|
|
|
accessor.SetValue(this, finalValue); |
|
|
|
} |
|
|
|
|
|
|
|
if (validated) |
|
|
|
if (metadata.EnableDataValidation) |
|
|
|
{ |
|
|
|
UpdateDataValidation(property, notification); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Converts an unset value to the default value for a direct property.
|
|
|
|
/// Sets the value of a styled property.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="value">The value.</param>
|
|
|
|
/// <param name="property">The property.</param>
|
|
|
|
/// <returns>The value.</returns>
|
|
|
|
private object DirectUnsetToDefault(object value, AvaloniaProperty property) |
|
|
|
/// <param name="value">The value.</param>
|
|
|
|
/// <param name="priority">The priority of the value.</param>
|
|
|
|
private void SetStyledValue(AvaloniaProperty property, object value, BindingPriority priority) |
|
|
|
{ |
|
|
|
return value == AvaloniaProperty.UnsetValue ? |
|
|
|
((IDirectPropertyMetadata)property.GetMetadata(GetType())).UnsetValue : |
|
|
|
value; |
|
|
|
} |
|
|
|
var notification = value as BindingNotification; |
|
|
|
|
|
|
|
/// <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) |
|
|
|
{ |
|
|
|
if (property.Inherits && _inheritanceParent != null) |
|
|
|
// We currently accept BindingNotifications for non-direct properties but we just
|
|
|
|
// strip them to their underlying value.
|
|
|
|
if (notification != null) |
|
|
|
{ |
|
|
|
return (_inheritanceParent as AvaloniaObject).GetValueInternal(property); |
|
|
|
if (!notification.HasValue) |
|
|
|
{ |
|
|
|
return; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
value = notification.Value; |
|
|
|
} |
|
|
|
} |
|
|
|
else |
|
|
|
|
|
|
|
var originalValue = value; |
|
|
|
|
|
|
|
if (!AvaloniaPropertyRegistry.Instance.IsRegistered(this, property)) |
|
|
|
{ |
|
|
|
return ((IStyledPropertyAccessor)property).GetDefaultValue(GetType()); |
|
|
|
ThrowNotRegistered(property); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/// <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)) |
|
|
|
if (!TypeUtilities.TryCast(property.PropertyType, value, out value)) |
|
|
|
{ |
|
|
|
result = value.Value; |
|
|
|
throw new ArgumentException(string.Format( |
|
|
|
"Invalid value for Property '{0}': '{1}' ({2})", |
|
|
|
property.Name, |
|
|
|
originalValue, |
|
|
|
originalValue?.GetType().FullName ?? "(null)")); |
|
|
|
} |
|
|
|
|
|
|
|
if (result == AvaloniaProperty.UnsetValue) |
|
|
|
PriorityValue v; |
|
|
|
|
|
|
|
if (!_values.TryGetValue(property, out v)) |
|
|
|
{ |
|
|
|
result = GetDefaultValue(property); |
|
|
|
if (value == AvaloniaProperty.UnsetValue) |
|
|
|
{ |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
v = CreatePriorityValue(property); |
|
|
|
_values.Add(property, v); |
|
|
|
} |
|
|
|
|
|
|
|
return result; |
|
|
|
LogPropertySet(property, value, priority); |
|
|
|
v.SetValue(value, (int)priority); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|