From c404dcf1c70357d07c5529212b4e8f492be6f491 Mon Sep 17 00:00:00 2001 From: artyom Date: Wed, 28 Oct 2020 22:36:56 +0300 Subject: [PATCH] Use GetObservable and AvaProperty.UnSet --- .../ReactiveUserControl.cs | 27 +++++-- src/Avalonia.ReactiveUI/ReactiveWindow.cs | 27 +++++-- .../ReactiveUserControlTest.cs | 71 +++++++++++++++++++ 3 files changed, 117 insertions(+), 8 deletions(-) diff --git a/src/Avalonia.ReactiveUI/ReactiveUserControl.cs b/src/Avalonia.ReactiveUI/ReactiveUserControl.cs index 31f4691c90..416f0a2165 100644 --- a/src/Avalonia.ReactiveUI/ReactiveUserControl.cs +++ b/src/Avalonia.ReactiveUI/ReactiveUserControl.cs @@ -29,10 +29,29 @@ namespace Avalonia.ReactiveUI // block if the ViewModel implements IActivatableViewModel. this.WhenActivated(disposables => { }); - this.ObservableForProperty(x => x.ViewModel, false, true) - .Subscribe(args => DataContext = args.Value); - this.ObservableForProperty(x => x.DataContext, false, true) - .Subscribe(args => ViewModel = args.Value as TViewModel); + this.GetObservable(DataContextProperty).Subscribe(value => + { + if (value is TViewModel viewModel) + { + ViewModel = viewModel; + } + else + { + ViewModel = null; + } + }); + + this.GetObservable(ViewModelProperty).Subscribe(value => + { + if (value == null) + { + DataContext = AvaloniaProperty.UnsetValue; + } + else + { + DataContext = value; + } + }); } /// diff --git a/src/Avalonia.ReactiveUI/ReactiveWindow.cs b/src/Avalonia.ReactiveUI/ReactiveWindow.cs index 1204266b63..fcef0a019f 100644 --- a/src/Avalonia.ReactiveUI/ReactiveWindow.cs +++ b/src/Avalonia.ReactiveUI/ReactiveWindow.cs @@ -29,10 +29,29 @@ namespace Avalonia.ReactiveUI // block if the ViewModel implements IActivatableViewModel. this.WhenActivated(disposables => { }); - this.ObservableForProperty(x => x.ViewModel, false, true) - .Subscribe(args => DataContext = args.Value); - this.ObservableForProperty(x => x.DataContext, false, true) - .Subscribe(args => ViewModel = args.Value as TViewModel); + this.GetObservable(DataContextProperty).Subscribe(value => + { + if (value is TViewModel viewModel) + { + ViewModel = viewModel; + } + else + { + ViewModel = null; + } + }); + + this.GetObservable(ViewModelProperty).Subscribe(value => + { + if (value == null) + { + DataContext = AvaloniaProperty.UnsetValue; + } + else + { + DataContext = value; + } + }); } /// diff --git a/tests/Avalonia.ReactiveUI.UnitTests/ReactiveUserControlTest.cs b/tests/Avalonia.ReactiveUI.UnitTests/ReactiveUserControlTest.cs index 5d257f75f2..4dd60e21c5 100644 --- a/tests/Avalonia.ReactiveUI.UnitTests/ReactiveUserControlTest.cs +++ b/tests/Avalonia.ReactiveUI.UnitTests/ReactiveUserControlTest.cs @@ -1,4 +1,5 @@ using System.Reactive.Disposables; +using Avalonia.Controls; using Avalonia.UnitTests; using ReactiveUI; using Splat; @@ -100,5 +101,75 @@ namespace Avalonia.ReactiveUI.UnitTests Assert.NotNull(view.DataContext); Assert.False(view.ViewModel.IsActive); } + + [Fact] + public void Should_Inherit_DataContext() + { + var vm1 = new ExampleViewModel(); + var vm2 = new ExampleViewModel(); + var view = new ExampleView(); + var root = new TestRoot(view); + + Assert.Null(view.DataContext); + Assert.Null(view.ViewModel); + + root.DataContext = vm1; + + Assert.Same(vm1, view.DataContext); + Assert.Same(vm1, view.ViewModel); + + root.DataContext = null; + + Assert.Null(view.DataContext); + Assert.Null(view.ViewModel); + + root.DataContext = vm2; + + Assert.Same(vm2, view.DataContext); + Assert.Same(vm2, view.ViewModel); + } + + [Fact] + public void Should_Not_Overlap_Change_Notifications() + { + var vm1 = new ExampleViewModel(); + var vm2 = new ExampleViewModel(); + + var view1 = new ExampleView(); + var view2 = new ExampleView(); + + Assert.Null(view1.DataContext); + Assert.Null(view2.DataContext); + Assert.Null(view1.ViewModel); + Assert.Null(view2.ViewModel); + + view1.DataContext = vm1; + + Assert.Same(vm1, view1.DataContext); + Assert.Same(vm1, view1.ViewModel); + Assert.Null(view2.DataContext); + Assert.Null(view2.ViewModel); + + view2.DataContext = vm2; + + Assert.Same(vm1, view1.DataContext); + Assert.Same(vm1, view1.ViewModel); + Assert.Same(vm2, view2.DataContext); + Assert.Same(vm2, view2.ViewModel); + + view1.ViewModel = null; + + Assert.Null(view1.DataContext); + Assert.Null(view1.ViewModel); + Assert.Same(vm2, view2.DataContext); + Assert.Same(vm2, view2.ViewModel); + + view2.ViewModel = null; + + Assert.Null(view1.DataContext); + Assert.Null(view2.DataContext); + Assert.Null(view1.ViewModel); + Assert.Null(view2.ViewModel); + } } }