diff --git a/src/Avalonia.Base/AvaloniaObject.cs b/src/Avalonia.Base/AvaloniaObject.cs index 91e087abc0..b5956d681a 100644 --- a/src/Avalonia.Base/AvaloniaObject.cs +++ b/src/Avalonia.Base/AvaloniaObject.cs @@ -54,7 +54,7 @@ namespace Avalonia /// /// Delayed setter helper for direct properties. Used to fix #855. /// - protected readonly DelayedSetter directDelayedSetter = new DelayedSetter(); + private readonly DelayedSetter directDelayedSetter = new DelayedSetter(); /// @@ -589,6 +589,30 @@ namespace Avalonia } } + protected void SetAndRaise(AvaloniaProperty property, Action> setterCallback, T value, Action delayedSet) + { + Contract.Requires(setterCallback != null); + Contract.Requires(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); + } + } + /// /// Tries to cast a value to a type, taking into account that the value may be a /// . diff --git a/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs b/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs index e5f5e8fc30..294b14b13d 100644 --- a/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs +++ b/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().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().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 { diff --git a/tests/Avalonia.Controls.UnitTests/Primitives/RangeBaseTests.cs b/tests/Avalonia.Controls.UnitTests/Primitives/RangeBaseTests.cs index 0e67581760..062ace2648 100644 --- a/tests/Avalonia.Controls.UnitTests/Primitives/RangeBaseTests.cs +++ b/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;