1
0
Эх сурвалжийг харах

Apply fix to PriorityValue, which works for StyledProperty bindings where the bindings don't have the same priority.

Jeremy Koritzinsky 8 жил өмнө
parent
commit
6486ffc77f

+ 50 - 33
src/Avalonia.Base/PriorityValue.cs

@@ -30,6 +30,7 @@ namespace Avalonia
         private readonly SingleOrDictionary<int, PriorityLevel> _levels = new SingleOrDictionary<int, PriorityLevel>();
         private object _value;
         private readonly Func<object, object> _validate;
+        private static readonly DelayedSetter<PriorityValue, (object value, int priority)> delayedSetter = new DelayedSetter<PriorityValue, (object, int)>();
 
         /// <summary>
         /// Initializes a new instance of the <see cref="PriorityValue"/> class.
@@ -234,51 +235,67 @@ namespace Avalonia
         /// <param name="priority">The priority level that the value came from.</param>
         private void UpdateValue(object value, int priority)
         {
-            var notification = value as BindingNotification;
-            object castValue;
-
-            if (notification != null)
-            {
-                value = (notification.HasValue) ? notification.Value : null;
-            }
-
-            if (TypeUtilities.TryConvertImplicit(_valueType, value, out castValue))
+            if (!delayedSetter.IsNotifying(this))
             {
-                var old = _value;
+                var notification = value as BindingNotification;
+                object castValue;
 
-                if (_validate != null && castValue != AvaloniaProperty.UnsetValue)
+                if (notification != null)
                 {
-                    castValue = _validate(castValue);
+                    value = (notification.HasValue) ? notification.Value : null;
                 }
 
-                ValuePriority = priority;
-                _value = castValue;
-
-                if (notification?.HasValue == true)
+                if (!object.Equals(value, _value) && TypeUtilities.TryConvertImplicit(_valueType, value, out castValue))
                 {
-                    notification.SetValue(castValue);
-                }
+                    var old = _value;
 
-                if (notification == null || notification.HasValue)
-                {
-                    Owner?.Changed(this, old, _value);
-                }
+                    if (_validate != null && castValue != AvaloniaProperty.UnsetValue)
+                    {
+                        castValue = _validate(castValue);
+                    }
 
-                if (notification != null)
-                {
-                    Owner?.BindingNotificationReceived(this, notification);
+                    ValuePriority = priority;
+                    _value = castValue;
+
+                    if (notification?.HasValue == true)
+                    {
+                        notification.SetValue(castValue);
+                    }
+
+                    if (notification == null || notification.HasValue)
+                    {
+                        using (delayedSetter.MarkNotifying(this))
+                        {
+                            Owner?.Changed(this, old, _value); 
+                        }
+
+                        if (delayedSetter.HasPendingSet(this))
+                        {
+                            var pendingSet = delayedSetter.GetFirstPendingSet(this);
+                            UpdateValue(pendingSet.value, pendingSet.priority);
+                        }
+                    }
+
+                    if (notification != null)
+                    {
+                        Owner?.BindingNotificationReceived(this, notification);
+                    }
                 }
+                else
+                {
+                    Logger.Error(
+                        LogArea.Binding,
+                        Owner,
+                        "Binding produced invalid value for {$Property} ({$PropertyType}): {$Value} ({$ValueType})",
+                        Property.Name,
+                        _valueType,
+                        value,
+                        value?.GetType());
+                } 
             }
             else
             {
-                Logger.Error(
-                    LogArea.Binding, 
-                    Owner,
-                    "Binding produced invalid value for {$Property} ({$PropertyType}): {$Value} ({$ValueType})",
-                    Property.Name, 
-                    _valueType, 
-                    value,
-                    value?.GetType());
+                delayedSetter.AddPendingSet(this, (value, priority));
             }
         }
     }

+ 1 - 1
tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Binding.cs

@@ -428,7 +428,7 @@ namespace Avalonia.Base.UnitTests
             //here in real life stack overflow exception is thrown issue #855 and #824
             target.DoubleValue = 51.001;
 
-            Assert.Equal(2, viewModel.SetterInvokedCount);
+            Assert.Equal(3, viewModel.SetterInvokedCount);
 
             double expected = 51;