diff --git a/src/Avalonia.Base/PriorityBindingEntry.cs b/src/Avalonia.Base/PriorityBindingEntry.cs index 95add0dfac..7f5415c2d8 100644 --- a/src/Avalonia.Base/PriorityBindingEntry.cs +++ b/src/Avalonia.Base/PriorityBindingEntry.cs @@ -99,37 +99,42 @@ namespace Avalonia void IObserver.OnNext(object value) { - void Signal() + void Signal(PriorityBindingEntry instance, object newValue) { - var notification = value as BindingNotification; + var notification = newValue as BindingNotification; if (notification != null) { if (notification.HasValue || notification.ErrorType == BindingErrorType.Error) { - Value = notification.Value; - _owner.Changed(this); + instance.Value = notification.Value; + instance._owner.Changed(instance); } if (notification.ErrorType != BindingErrorType.None) { - _owner.Error(this, notification); + instance._owner.Error(instance, notification); } } else { - Value = value; - _owner.Changed(this); + instance.Value = newValue; + instance._owner.Changed(instance); } } if (Dispatcher.UIThread.CheckAccess()) { - Signal(); + Signal(this, value); } else { - Dispatcher.UIThread.Post(Signal); + // To avoid allocating closure in the outer scope we need to capture variables + // locally. This allows us to skip most of the allocations when on UI thread. + var instance = this; + var newValue = value; + + Dispatcher.UIThread.Post(() => Signal(instance, newValue)); } } diff --git a/src/Avalonia.Base/PriorityLevel.cs b/src/Avalonia.Base/PriorityLevel.cs index 909558b0ce..6366911e77 100644 --- a/src/Avalonia.Base/PriorityLevel.cs +++ b/src/Avalonia.Base/PriorityLevel.cs @@ -110,20 +110,7 @@ namespace Avalonia entry.Start(binding); - return Disposable.Create(() => - { - if (!entry.HasCompleted) - { - Bindings.Remove(node); - - entry.Dispose(); - - if (entry.Index >= ActiveBindingIndex) - { - ActivateFirstBinding(); - } - } - }); + return new RemoveBindingDisposable(node, Bindings, this); } /// @@ -191,5 +178,39 @@ namespace Avalonia ActiveBindingIndex = -1; Owner.LevelValueChanged(this); } + + private sealed class RemoveBindingDisposable : IDisposable + { + private readonly LinkedListNode _binding; + private readonly LinkedList _bindings; + private readonly PriorityLevel _priorityLevel; + + public RemoveBindingDisposable( + LinkedListNode binding, + LinkedList bindings, + PriorityLevel priorityLevel) + { + _binding = binding; + _bindings = bindings; + _priorityLevel = priorityLevel; + } + + public void Dispose() + { + PriorityBindingEntry entry = _binding.Value; + + if (!entry.HasCompleted) + { + _bindings.Remove(_binding); + + entry.Dispose(); + + if (entry.Index >= _priorityLevel.ActiveBindingIndex) + { + _priorityLevel.ActivateFirstBinding(); + } + } + } + } } }