diff --git a/build.cake b/build.cake
index 24f529ee4a..56653109ae 100644
--- a/build.cake
+++ b/build.cake
@@ -170,6 +170,7 @@ Task("Run-Unit-Tests-Impl")
RunCoreTest("./tests/Avalonia.Styling.UnitTests", data.Parameters, false);
RunCoreTest("./tests/Avalonia.Visuals.UnitTests", data.Parameters, false);
RunCoreTest("./tests/Avalonia.Skia.UnitTests", data.Parameters, false);
+ RunCoreTest("./tests/Avalonia.ReactiveUI.UnitTests", data.Parameters, false);
if (data.Parameters.IsRunningOnWindows)
{
RunCoreTest("./tests/Avalonia.Direct2D1.UnitTests", data.Parameters, false);
diff --git a/build/ReactiveUI.props b/build/ReactiveUI.props
index acdfdd215a..1208be34b8 100644
--- a/build/ReactiveUI.props
+++ b/build/ReactiveUI.props
@@ -1,5 +1,5 @@
-
+
diff --git a/samples/VirtualizationDemo/ViewModels/MainWindowViewModel.cs b/samples/VirtualizationDemo/ViewModels/MainWindowViewModel.cs
index eb08ef9656..eba17f92e4 100644
--- a/samples/VirtualizationDemo/ViewModels/MainWindowViewModel.cs
+++ b/samples/VirtualizationDemo/ViewModels/MainWindowViewModel.cs
@@ -7,6 +7,7 @@ using System.Linq;
using Avalonia.Collections;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
+using ReactiveUI.Legacy;
using ReactiveUI;
namespace VirtualizationDemo.ViewModels
diff --git a/src/Avalonia.ReactiveUI/AppBuilderExtensions.cs b/src/Avalonia.ReactiveUI/AppBuilderExtensions.cs
index 3eab54115a..d763febdf3 100644
--- a/src/Avalonia.ReactiveUI/AppBuilderExtensions.cs
+++ b/src/Avalonia.ReactiveUI/AppBuilderExtensions.cs
@@ -4,6 +4,7 @@
using Avalonia.Controls;
using Avalonia.Threading;
using ReactiveUI;
+using Splat;
namespace Avalonia
{
@@ -15,6 +16,9 @@ namespace Avalonia
return builder.AfterSetup(_ =>
{
RxApp.MainThreadScheduler = AvaloniaScheduler.Instance;
+ Locator.CurrentMutable.Register(
+ () => new AvaloniaActivationForViewFetcher(),
+ typeof(IActivationForViewFetcher));
});
}
}
diff --git a/src/Avalonia.ReactiveUI/AvaloniaActivationForViewFetcher.cs b/src/Avalonia.ReactiveUI/AvaloniaActivationForViewFetcher.cs
new file mode 100644
index 0000000000..828d8024e6
--- /dev/null
+++ b/src/Avalonia.ReactiveUI/AvaloniaActivationForViewFetcher.cs
@@ -0,0 +1,38 @@
+// Copyright (c) The Avalonia Project. All rights reserved.
+// Licensed under the MIT license. See licence.md file in the project root for full license information.
+
+using System;
+using System.Reflection;
+using System.Reactive.Linq;
+using Avalonia;
+using Avalonia.VisualTree;
+using ReactiveUI;
+
+namespace Avalonia
+{
+ public class AvaloniaActivationForViewFetcher : IActivationForViewFetcher
+ {
+ public int GetAffinityForView(Type view)
+ {
+ return typeof(IVisual).GetTypeInfo().IsAssignableFrom(view.GetTypeInfo()) ? 10 : 0;
+ }
+
+ public IObservable GetActivationForView(IActivatable view)
+ {
+ if (!(view is IVisual visual)) return Observable.Return(false);
+ var viewLoaded = Observable
+ .FromEventPattern(
+ x => visual.AttachedToVisualTree += x,
+ x => visual.DetachedFromVisualTree -= x)
+ .Select(args => true);
+ var viewUnloaded = Observable
+ .FromEventPattern(
+ x => visual.DetachedFromVisualTree += x,
+ x => visual.DetachedFromVisualTree -= x)
+ .Select(args => false);
+ return viewLoaded
+ .Merge(viewUnloaded)
+ .DistinctUntilChanged();
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/Avalonia.ReactiveUI.UnitTests/Avalonia.ReactiveUI.UnitTests.csproj b/tests/Avalonia.ReactiveUI.UnitTests/Avalonia.ReactiveUI.UnitTests.csproj
new file mode 100644
index 0000000000..7c0ff79183
--- /dev/null
+++ b/tests/Avalonia.ReactiveUI.UnitTests/Avalonia.ReactiveUI.UnitTests.csproj
@@ -0,0 +1,14 @@
+
+
+ netcoreapp2.0
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/Avalonia.ReactiveUI.UnitTests/AvaloniaActivationForViewFetcherTest.cs b/tests/Avalonia.ReactiveUI.UnitTests/AvaloniaActivationForViewFetcherTest.cs
new file mode 100644
index 0000000000..97701f8437
--- /dev/null
+++ b/tests/Avalonia.ReactiveUI.UnitTests/AvaloniaActivationForViewFetcherTest.cs
@@ -0,0 +1,89 @@
+using System;
+using System.Reactive.Concurrency;
+using System.Reactive.Disposables;
+using Avalonia.Controls;
+using Avalonia.Rendering;
+using Avalonia.Platform;
+using Avalonia.UnitTests;
+using Avalonia;
+using ReactiveUI;
+using DynamicData;
+using Xunit;
+using Splat;
+
+namespace Avalonia
+{
+ public class AvaloniaActivationForViewFetcherTest
+ {
+ public class TestUserControl : UserControl, IActivatable { }
+
+ public class TestUserControlWithWhenActivated : UserControl, IActivatable
+ {
+ public bool Active { get; private set; }
+
+ public TestUserControlWithWhenActivated()
+ {
+ this.WhenActivated(disposables => {
+ Active = true;
+ Disposable
+ .Create(() => Active = false)
+ .DisposeWith(disposables);
+ });
+ }
+ }
+
+ [Fact]
+ public void Visual_Element_Is_Activated_And_Deactivated()
+ {
+ var userControl = new TestUserControl();
+ var activationForViewFetcher = new AvaloniaActivationForViewFetcher();
+
+ activationForViewFetcher
+ .GetActivationForView(userControl)
+ .ToObservableChangeSet(scheduler: ImmediateScheduler.Instance)
+ .Bind(out var activated)
+ .Subscribe();
+
+ var fakeRenderedDecorator = new TestRoot();
+ fakeRenderedDecorator.Child = userControl;
+ Assert.True(activated[0]);
+ Assert.Equal(1, activated.Count);
+
+ fakeRenderedDecorator.Child = null;
+ Assert.True(activated[0]);
+ Assert.False(activated[1]);
+ Assert.Equal(2, activated.Count);
+ }
+
+ [Fact]
+ public void Get_Affinity_For_View_Should_Return_Non_Zero_For_Visual_Elements()
+ {
+ var userControl = new TestUserControl();
+ var activationForViewFetcher = new AvaloniaActivationForViewFetcher();
+
+ var forUserControl = activationForViewFetcher.GetAffinityForView(userControl.GetType());
+ var forNonUserControl = activationForViewFetcher.GetAffinityForView(typeof(object));
+
+ Assert.NotEqual(0, forUserControl);
+ Assert.Equal(0, forNonUserControl);
+ }
+
+ [Fact]
+ public void Activation_For_View_Fetcher_Should_Support_When_Activated()
+ {
+ Locator.CurrentMutable.RegisterConstant(
+ new AvaloniaActivationForViewFetcher(),
+ typeof(IActivationForViewFetcher));
+
+ var userControl = new TestUserControlWithWhenActivated();
+ Assert.False(userControl.Active);
+
+ var fakeRenderedDecorator = new TestRoot();
+ fakeRenderedDecorator.Child = userControl;
+ Assert.True(userControl.Active);
+
+ fakeRenderedDecorator.Child = null;
+ Assert.False(userControl.Active);
+ }
+ }
+}
\ No newline at end of file