diff --git a/src/Avalonia.Base/PropertyStore/ValueFrame.cs b/src/Avalonia.Base/PropertyStore/ValueFrame.cs index 90714ec5ac..5ada4b3c84 100644 --- a/src/Avalonia.Base/PropertyStore/ValueFrame.cs +++ b/src/Avalonia.Base/PropertyStore/ValueFrame.cs @@ -4,6 +4,7 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using Avalonia.Data; using Avalonia.Utilities; +using static Avalonia.Rendering.Composition.Animations.PropertySetSnapshot; namespace Avalonia.PropertyStore { @@ -45,8 +46,9 @@ namespace Avalonia.PropertyStore public void OnBindingCompleted(IValueEntry binding) { - Remove(binding.Property); - Owner?.OnBindingCompleted(binding.Property, this); + var property = binding.Property; + Remove(property); + Owner?.OnValueEntryRemoved(this, property); } public virtual void Dispose() diff --git a/src/Avalonia.Base/PropertyStore/ValueStore.cs b/src/Avalonia.Base/PropertyStore/ValueStore.cs index 8d7fae41bf..bbc71f1a38 100644 --- a/src/Avalonia.Base/PropertyStore/ValueStore.cs +++ b/src/Avalonia.Base/PropertyStore/ValueStore.cs @@ -397,23 +397,6 @@ namespace Avalonia.PropertyStore } } - /// - /// Called by a to re-evaluate the - /// effective value when the binding completes or terminates on error. - /// - /// The previously bound property. - /// The frame which contained the binding. - public void OnBindingCompleted(AvaloniaProperty property, ValueFrame frame) - { - var priority = frame.Priority; - - if (TryGetEffectiveValue(property, out var existing)) - { - if (priority <= existing.Priority) - ReevaluateEffectiveValue(property, existing); - } - } - /// /// Called by a when its /// state changes. @@ -577,22 +560,14 @@ namespace Avalonia.PropertyStore /// The property whose value was removed. public void OnValueEntryRemoved(ValueFrame frame, AvaloniaProperty property) { - Debug.Assert(frame.IsActive); + if (frame.EntryCount == 0) + _frames.Remove(frame); if (TryGetEffectiveValue(property, out var existing)) { if (frame.Priority <= existing.Priority) ReevaluateEffectiveValue(property, existing); } - else - { - Logger.TryGet(LogEventLevel.Error, LogArea.Property)?.Log( - Owner, - "Internal error: ValueStore.OnEntryRemoved called for {Property} " + - "but no effective value was found.", - property); - Debug.Assert(false); - } } public bool RemoveFrame(ValueFrame frame) diff --git a/tests/Avalonia.Base.UnitTests/PropertyStore/ValueStoreTests_Frames.cs b/tests/Avalonia.Base.UnitTests/PropertyStore/ValueStoreTests_Frames.cs index 48bc21dc5f..bb726a1d63 100644 --- a/tests/Avalonia.Base.UnitTests/PropertyStore/ValueStoreTests_Frames.cs +++ b/tests/Avalonia.Base.UnitTests/PropertyStore/ValueStoreTests_Frames.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; -using System.Reactive; using System.Reactive.Subjects; +using Avalonia.Data; using Avalonia.PropertyStore; using Avalonia.Styling; using Microsoft.Reactive.Testing; @@ -80,7 +80,6 @@ namespace Avalonia.Base.UnitTests.PropertyStore var target = new Class1(); var scheduler = new TestScheduler(); var obs = scheduler.CreateColdObservable(OnNext(0, "bar")); - var result = new List(); var style = new Style { Setters = @@ -99,6 +98,23 @@ namespace Avalonia.Base.UnitTests.PropertyStore Assert.NotEqual(Subscription.Infinite, obs.Subscriptions[0].Unsubscribe); } + [Fact] + public void Completing_Binding_Removes_ImmediateValueFrame() + { + var target = new Class1(); + var source = new BehaviorSubject>("foo"); + + target.Bind(Class1.FooProperty, source, BindingPriority.Animation); + + var valueStore = target.GetValueStore(); + Assert.Equal(1, valueStore.Frames.Count); + Assert.IsType(valueStore.Frames[0]); + + source.OnCompleted(); + + Assert.Equal(0, valueStore.Frames.Count); + } + private static StyleInstance InstanceStyle(Style style, StyledElement target) { var result = new StyleInstance(style, null);