Browse Source

Add ReactiveUserControl and ReactiveWindow

pull/1989/head
artyom 8 years ago
parent
commit
d2be495bde
  1. 45
      src/Avalonia.ReactiveUI/ReactiveUserControl.cs
  2. 45
      src/Avalonia.ReactiveUI/ReactiveWindow.cs
  3. 82
      tests/Avalonia.ReactiveUI.UnitTests/AvaloniaActivationForViewFetcherTest.cs

45
src/Avalonia.ReactiveUI/ReactiveUserControl.cs

@ -0,0 +1,45 @@
// 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 Avalonia;
using Avalonia.VisualTree;
using Avalonia.Controls;
using ReactiveUI;
namespace Avalonia
{
/// <summary>
/// A ReactiveUI UserControl that implements <see cref="IViewFor{TViewModel}"/>
/// and will activate your ViewModel automatically if it supports activation.
/// </summary>
/// <typeparam name="TViewModel">ViewModel type.</typeparam>
public class ReactiveUserControl<TViewModel> : UserControl, IViewFor<TViewModel> where TViewModel : class
{
public static readonly AvaloniaProperty<TViewModel> ViewModelProperty = AvaloniaProperty
.Register<ReactiveWindow<TViewModel>, TViewModel>(nameof(ViewModel));
/// <summary>
/// Initializes a new instance of the <see cref="ReactiveUserControl{TViewModel}"/> class.
/// </summary>
public ReactiveUserControl()
{
DataContextChanged += (sender, args) => ViewModel = DataContext as TViewModel;
this.WhenActivated(disposables => { /* activate ViewModel */ });
}
/// <summary>
/// The ViewModel.
/// </summary>
public TViewModel ViewModel
{
get => GetValue(ViewModelProperty);
set => SetValue(ViewModelProperty, value);
}
object IViewFor.ViewModel
{
get => ViewModel;
set => ViewModel = (TViewModel)value;
}
}
}

45
src/Avalonia.ReactiveUI/ReactiveWindow.cs

@ -0,0 +1,45 @@
// 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 Avalonia;
using Avalonia.VisualTree;
using Avalonia.Controls;
using ReactiveUI;
namespace Avalonia
{
/// <summary>
/// A ReactiveUI Window that implements <see cref="IViewFor{TViewModel}"/>
/// and will activate your ViewModel automatically if it supports activation.
/// </summary>
/// <typeparam name="TViewModel">ViewModel type.</typeparam>
public class ReactiveWindow<TViewModel> : Window, IViewFor<TViewModel> where TViewModel : class
{
public static readonly AvaloniaProperty<TViewModel> ViewModelProperty = AvaloniaProperty
.Register<ReactiveWindow<TViewModel>, TViewModel>(nameof(ViewModel));
/// <summary>
/// Initializes a new instance of the <see cref="ReactiveWindow{TViewModel}"/> class.
/// </summary>
public ReactiveWindow()
{
DataContextChanged += (sender, args) => ViewModel = DataContext as TViewModel;
this.WhenActivated(disposables => { /* activate ViewModel */ });
}
/// <summary>
/// The ViewModel.
/// </summary>
public TViewModel ViewModel
{
get => GetValue(ViewModelProperty);
set => SetValue(ViewModelProperty, value);
}
object IViewFor.ViewModel
{
get => ViewModel;
set => ViewModel = (TViewModel)value;
}
}
}

82
tests/Avalonia.ReactiveUI.UnitTests/AvaloniaActivationForViewFetcherTest.cs

@ -23,7 +23,8 @@ namespace Avalonia
public TestUserControlWithWhenActivated()
{
this.WhenActivated(disposables => {
this.WhenActivated(disposables =>
{
Active = true;
Disposable
.Create(() => Active = false)
@ -38,7 +39,8 @@ namespace Avalonia
public TestWindowWithWhenActivated()
{
this.WhenActivated(disposables => {
this.WhenActivated(disposables =>
{
Active = true;
Disposable
.Create(() => Active = false)
@ -47,6 +49,42 @@ namespace Avalonia
}
}
public class ActivatableViewModel : ISupportsActivation
{
public ViewModelActivator Activator { get; }
public bool IsActivated { get; private set; }
public ActivatableViewModel()
{
Activator = new ViewModelActivator();
this.WhenActivated(disposables =>
{
IsActivated = true;
Disposable
.Create(() => IsActivated = false)
.DisposeWith(disposables);
});
}
}
public class ActivatableWindow : ReactiveWindow<ActivatableViewModel>
{
public ActivatableWindow() { }
}
public class ActivatableUserControl : ReactiveUserControl<ActivatableViewModel>
{
public ActivatableUserControl() { }
}
public AvaloniaActivationForViewFetcherTest()
{
Locator.CurrentMutable.RegisterConstant(
new AvaloniaActivationForViewFetcher(),
typeof(IActivationForViewFetcher));
}
[Fact]
public void Visual_Element_Is_Activated_And_Deactivated()
{
@ -86,10 +124,6 @@ namespace Avalonia
[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);
@ -104,10 +138,6 @@ namespace Avalonia
[Fact]
public void Activation_For_View_Fetcher_Should_Support_Windows()
{
Locator.CurrentMutable.RegisterConstant(
new AvaloniaActivationForViewFetcher(),
typeof(IActivationForViewFetcher));
using (var application = UnitTestApplication.Start(TestServices.MockWindowingPlatform))
{
var window = new TestWindowWithWhenActivated();
@ -120,5 +150,37 @@ namespace Avalonia
Assert.False(window.Active);
}
}
[Fact]
public void Activatable_Window_View_Model_Is_Activated_And_Deactivated()
{
using (var application = UnitTestApplication.Start(TestServices.MockWindowingPlatform))
{
var viewModel = new ActivatableViewModel();
var window = new ActivatableWindow { ViewModel = viewModel };
Assert.False(viewModel.IsActivated);
window.Show();
Assert.True(viewModel.IsActivated);
window.Close();
Assert.False(viewModel.IsActivated);
}
}
[Fact]
public void Activatable_User_Control_View_Model_Is_Activated_And_Deactivated()
{
var root = new TestRoot();
var viewModel = new ActivatableViewModel();
var control = new ActivatableUserControl { ViewModel = viewModel };
Assert.False(viewModel.IsActivated);
root.Child = control;
Assert.True(viewModel.IsActivated);
root.Child = null;
Assert.False(viewModel.IsActivated);
}
}
}
Loading…
Cancel
Save