From b5891a2ead2825d688f24cbb72f0dc085f73fbb8 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Sat, 15 Oct 2022 00:40:35 +0200 Subject: [PATCH] Fix bug in ExpressionObserver. Ensure `rootGetter` is evaluated each time the observer is initialized; plus failing and now passing test. --- .../Data/Core/ExpressionObserver.cs | 9 ++++--- .../Core/ExpressionObserverTests_Property.cs | 27 +++++++++++++++---- 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/src/Avalonia.Base/Data/Core/ExpressionObserver.cs b/src/Avalonia.Base/Data/Core/ExpressionObserver.cs index e4affd97de..0c7f576da6 100644 --- a/src/Avalonia.Base/Data/Core/ExpressionObserver.cs +++ b/src/Avalonia.Base/Data/Core/ExpressionObserver.cs @@ -52,6 +52,7 @@ namespace Avalonia.Data.Core private static readonly object UninitializedValue = new object(); private readonly ExpressionNode _node; private object? _root; + private Func? _rootGetter; private IDisposable? _rootSubscription; private WeakReference? _value; private IReadOnlyList? _transformNodes; @@ -109,11 +110,9 @@ namespace Avalonia.Data.Core IObservable update, string? description) { - _ = rootGetter ?? throw new ArgumentNullException(nameof(rootGetter)); - Description = description; - _node = node ?? throw new ArgumentNullException(nameof(rootGetter)); - _node.Target = new WeakReference(rootGetter()); + _rootGetter = rootGetter ?? throw new ArgumentNullException(nameof(rootGetter)); + _node = node ?? throw new ArgumentNullException(nameof(node)); _root = update.Select(x => rootGetter()); } @@ -263,6 +262,8 @@ namespace Avalonia.Data.Core protected override void Initialize() { _value = null; + if (_rootGetter is not null) + _node.Target = new WeakReference(_rootGetter()); _node.Subscribe(ValueChanged); StartRoot(); } diff --git a/tests/Avalonia.Base.UnitTests/Data/Core/ExpressionObserverTests_Property.cs b/tests/Avalonia.Base.UnitTests/Data/Core/ExpressionObserverTests_Property.cs index a9c62a3c4a..f911048960 100644 --- a/tests/Avalonia.Base.UnitTests/Data/Core/ExpressionObserverTests_Property.cs +++ b/tests/Avalonia.Base.UnitTests/Data/Core/ExpressionObserverTests_Property.cs @@ -3,14 +3,13 @@ using System.Collections.Generic; using System.Reactive; using System.Reactive.Linq; using System.Reactive.Subjects; -using Microsoft.Reactive.Testing; +using System.Threading.Tasks; using Avalonia.Data; using Avalonia.Data.Core; +using Avalonia.Threading; using Avalonia.UnitTests; +using Microsoft.Reactive.Testing; using Xunit; -using System.Threading.Tasks; -using Avalonia.Markup.Parsers; -using Avalonia.Threading; namespace Avalonia.Base.UnitTests.Data.Core { @@ -636,7 +635,25 @@ namespace Avalonia.Base.UnitTests.Data.Core target.Subscribe(x => result.Add(x)); } - + + [Fact] + public void RootGetter_Is_Reevaluated_On_Subscribe() + { + var data = "foo"; + var target = new ExpressionObserver(() => data, new EmptyExpressionNode(), new Subject(), null); + var result = new List(); + var sub = target.Subscribe(x => result.Add(x)); + + Assert.Equal(new object[] { "foo" }, result); + + sub.Dispose(); + data = "bar"; + + target.Subscribe(x => result.Add(x)); + + Assert.Equal(new object[] { "foo", "bar" }, result); + } + public class MyViewModelBase { public object Name => "Name"; } public class MyViewModel : MyViewModelBase { public new string Name => "NewName"; }