diff --git a/src/Avalonia.Base/ValueStore.cs b/src/Avalonia.Base/ValueStore.cs index 562cc165df..e1e399b4b3 100644 --- a/src/Avalonia.Base/ValueStore.cs +++ b/src/Avalonia.Base/ValueStore.cs @@ -1,16 +1,14 @@ using System; using System.Collections.Generic; -using System.Text; using Avalonia.Data; -using Avalonia.Utilities; namespace Avalonia { internal class ValueStore : IPriorityValueOwner { private readonly AvaloniaObject _owner; - private readonly Dictionary _values = - new Dictionary(); + private readonly Dictionary _values = + new Dictionary(); public ValueStore(AvaloniaObject owner) { @@ -22,51 +20,94 @@ namespace Avalonia IObservable source, BindingPriority priority) { - if (!_values.TryGetValue(property, out PriorityValue v)) + PriorityValue priorityValue; + + if (_values.TryGetValue(property, out var v)) + { + priorityValue = v as PriorityValue; + + if (priorityValue == null) + { + priorityValue = CreatePriorityValue(property); + priorityValue.SetValue(v, (int)BindingPriority.LocalValue); + _values[property] = priorityValue; + } + } + else { - v = CreatePriorityValue(property); - _values.Add(property, v); + priorityValue = CreatePriorityValue(property); + _values.Add(property, priorityValue); } - return v.Add(source, (int)priority); + return priorityValue.Add(source, (int)priority); } public void AddValue(AvaloniaProperty property, object value, int priority) { - var originalValue = value; + PriorityValue priorityValue; - if (!TypeUtilities.TryConvertImplicit(property.PropertyType, value, out value)) + if (_values.TryGetValue(property, out var v)) { - throw new ArgumentException(string.Format( - "Invalid value for Property '{0}': '{1}' ({2})", - property.Name, - originalValue, - originalValue?.GetType().FullName ?? "(null)")); - } + priorityValue = v as PriorityValue; - if (!_values.TryGetValue(property, out PriorityValue v)) + if (priorityValue == null) + { + if (priority == (int)BindingPriority.LocalValue) + { + _values[property] = Validate(property, value); + Changed(property, priority, v, value); + return; + } + else + { + priorityValue = CreatePriorityValue(property); + priorityValue.SetValue(v, (int)BindingPriority.LocalValue); + _values[property] = priorityValue; + } + } + } + else { if (value == AvaloniaProperty.UnsetValue) { return; } - v = CreatePriorityValue(property); - _values.Add(property, v); + if (priority == (int)BindingPriority.LocalValue) + { + _values.Add(property, Validate(property, value)); + Changed(property, priority, AvaloniaProperty.UnsetValue, value); + return; + } + else + { + priorityValue = CreatePriorityValue(property); + _values.Add(property, priorityValue); + } } - v.SetValue(value, priority); + priorityValue.SetValue(value, priority); } - public IDictionary GetSetValues() => _values; + public void BindingNotificationReceived(AvaloniaProperty property, BindingNotification notification) + { + ((IPriorityValueOwner)_owner).BindingNotificationReceived(property, notification); + } + + public void Changed(AvaloniaProperty property, int priority, object oldValue, object newValue) + { + ((IPriorityValueOwner)_owner).Changed(property, priority, oldValue, newValue); + } + + public IDictionary GetSetValues() => throw new NotImplementedException(); public object GetValue(AvaloniaProperty property) { var result = AvaloniaProperty.UnsetValue; - if (_values.TryGetValue(property, out PriorityValue value)) + if (_values.TryGetValue(property, out var value)) { - result = value.Value; + result = (value is PriorityValue priorityValue) ? priorityValue.Value : value; } if (result == AvaloniaProperty.UnsetValue) @@ -79,14 +120,14 @@ namespace Avalonia public bool IsAnimating(AvaloniaProperty property) { - return _values.TryGetValue(property, out PriorityValue value) ? value.IsAnimating : false; + return _values.TryGetValue(property, out var value) ? (value as PriorityValue)?.IsAnimating ?? false : false; } public bool IsSet(AvaloniaProperty property) { - if (_values.TryGetValue(property, out PriorityValue value)) + if (_values.TryGetValue(property, out var value)) { - return value.Value != AvaloniaProperty.UnsetValue; + return ((value as PriorityValue)?.Value ?? value) != AvaloniaProperty.UnsetValue; } return false; @@ -94,23 +135,13 @@ namespace Avalonia public void Revalidate(AvaloniaProperty property) { - if (_values.TryGetValue(property, out PriorityValue value)) + if (_values.TryGetValue(property, out var value)) { - value.Revalidate(); + (value as PriorityValue)?.Revalidate(); } } - void IPriorityValueOwner.BindingNotificationReceived(AvaloniaProperty property, BindingNotification notification) - { - ((IPriorityValueOwner)_owner).BindingNotificationReceived(property, notification); - } - - void IPriorityValueOwner.Changed(AvaloniaProperty property, int priority, object oldValue, object newValue) - { - ((IPriorityValueOwner)_owner).Changed(property, priority, oldValue, newValue); - } - - void IPriorityValueOwner.VerifyAccess() => _owner.VerifyAccess(); + public void VerifyAccess() => _owner.VerifyAccess(); private PriorityValue CreatePriorityValue(AvaloniaProperty property) { @@ -130,5 +161,17 @@ namespace Avalonia return result; } + + private object Validate(AvaloniaProperty property, object value) + { + var validate = ((IStyledPropertyAccessor)property).GetValidationFunc(_owner.GetType()); + + if (validate != null && value != AvaloniaProperty.UnsetValue) + { + return validate(_owner, value); + } + + return value; + } } }