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

Fix SelectedItemsControl and RangeBase Stackoverflow bugs.

Jeremy Koritzinsky 8 жил өмнө
parent
commit
440f2cafc5

+ 25 - 1
src/Avalonia.Base/AvaloniaObject.cs

@@ -54,7 +54,7 @@ namespace Avalonia
         /// <summary>
         /// Delayed setter helper for direct properties. Used to fix #855.
         /// </summary>
-        protected readonly DelayedSetter<AvaloniaProperty, object> directDelayedSetter = new DelayedSetter<AvaloniaProperty, object>();
+        private readonly DelayedSetter<AvaloniaProperty, object> directDelayedSetter = new DelayedSetter<AvaloniaProperty, object>();
 
 
         /// <summary>
@@ -589,6 +589,30 @@ namespace Avalonia
             }
         }
 
+        protected void SetAndRaise<T>(AvaloniaProperty<T> property, Action<T, Action<Action>> setterCallback, T value, Action<T> delayedSet)
+        {
+            Contract.Requires<ArgumentNullException>(setterCallback != null);
+            Contract.Requires<ArgumentNullException>(delayedSet != null);
+            if (!directDelayedSetter.IsNotifying(property))
+            {
+                setterCallback(value, notification => 
+                {
+                    using (directDelayedSetter.MarkNotifying(property))
+                    {
+                        notification();
+                    }
+                });
+                if (directDelayedSetter.HasPendingSet(property))
+                {
+                    delayedSet((T)directDelayedSetter.GetFirstPendingSet(property));
+                }
+            }
+            else
+            {
+                directDelayedSetter.AddPendingSet(property, value);
+            }
+        }
+
         /// <summary>
         /// Tries to cast a value to a type, taking into account that the value may be a
         /// <see cref="BindingNotification"/>.

+ 18 - 26
src/Avalonia.Controls/Primitives/SelectingItemsControl.cs

@@ -151,15 +151,18 @@ namespace Avalonia.Controls.Primitives
             {
                 if (_updateCount == 0)
                 {
-                    var old = SelectedIndex;
-                    var effective = (value >= 0 && value < Items?.Cast<object>().Count()) ? value : -1;
-
-                    if (old != effective)
+                    SetAndRaise(SelectedIndexProperty, (val, notifierWrapper) =>
                     {
-                        _selectedIndex = effective;
-                        RaisePropertyChanged(SelectedIndexProperty, old, effective, BindingPriority.LocalValue);
-                        SelectedItem = ElementAt(Items, effective);
-                    }
+                        var old = SelectedIndex;
+                        var effective = (val >= 0 && val < Items?.Cast<object>().Count()) ? val : -1;
+
+                        if (old != effective)
+                        {
+                            _selectedIndex = effective;
+                            notifierWrapper(() => RaisePropertyChanged(SelectedIndexProperty, old, effective, BindingPriority.LocalValue));
+                            SelectedItem = ElementAt(Items, effective);
+                        }
+                    }, value, val => SelectedIndex = val);
                 }
                 else
                 {
@@ -183,19 +186,17 @@ namespace Avalonia.Controls.Primitives
             {
                 if (_updateCount == 0)
                 {
-                    if (!directDelayedSetter.IsNotifying(SelectedItemProperty))
+                    SetAndRaise(SelectedItemProperty, (val, notifyWrapper) =>
                     {
                         var old = SelectedItem;
-                        var index = IndexOf(Items, value);
-                        var effective = index != -1 ? value : null;
+                        var index = IndexOf(Items, val);
+                        var effective = index != -1 ? val : null;
 
                         if (!object.Equals(effective, old))
                         {
                             _selectedItem = effective;
-                            using (directDelayedSetter.MarkNotifying(SelectedItemProperty))
-                            {
-                                RaisePropertyChanged(SelectedItemProperty, old, effective, BindingPriority.LocalValue);
-                            }
+
+                            notifyWrapper(() => RaisePropertyChanged(SelectedItemProperty, old, effective, BindingPriority.LocalValue));
 
                             SelectedIndex = index;
 
@@ -213,17 +214,8 @@ namespace Avalonia.Controls.Primitives
                             {
                                 SelectedItems.Clear();
                             }
-
-                            if (directDelayedSetter.HasPendingSet(SelectedItemProperty))
-                            {
-                                SelectedItem = directDelayedSetter.GetFirstPendingSet(SelectedItemProperty);
-                            }
-                        } 
-                    }
-                    else
-                    {
-                        directDelayedSetter.AddPendingSet(SelectedItemProperty, value);
-                    }
+                        }
+                    }, value, val => SelectedItem = val);
                 }
                 else
                 {

+ 1 - 1
tests/Avalonia.Controls.UnitTests/Primitives/RangeBaseTests.cs

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