Skip to content

Commit

Permalink
Merge branch 'develop' into tidying-comments-activation
Browse files Browse the repository at this point in the history
  • Loading branch information
olevett committed Feb 13, 2017
2 parents 69c8e98 + 8e9963f commit 3300405
Show file tree
Hide file tree
Showing 6 changed files with 129 additions and 27 deletions.
@@ -1,12 +1,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using System.Reactive.Subjects;
using System.Text;
using System.Threading.Tasks;
using Splat;
using Xunit;

Expand All @@ -21,7 +18,7 @@ public class ActivatingViewModel : ReactiveObject, ISupportsActivation
public ActivatingViewModel()
{
Activator = new ViewModelActivator();

this.WhenActivated(d => {
IsActiveCount++;
d(Disposable.Create(() => IsActiveCount--));
Expand All @@ -45,12 +42,14 @@ public DerivedActivatingViewModel()
public class ActivatingView : ReactiveObject, IViewFor<ActivatingViewModel>
{
ActivatingViewModel viewModel;
public ActivatingViewModel ViewModel {
public ActivatingViewModel ViewModel
{
get { return viewModel; }
set { this.RaiseAndSetIfChanged(ref viewModel, value); }
}

object IViewFor.ViewModel {
object IViewFor.ViewModel
{
get { return ViewModel; }
set { ViewModel = (ActivatingViewModel)value; }
}
Expand Down Expand Up @@ -248,8 +247,7 @@ public void CanUnloadAndLoadViewAgain()
locator.InitializeReactiveUI();
locator.Register(() => new ActivatingViewFetcher(), typeof(IActivationForViewFetcher));

using (locator.WithResolver())
{
using (locator.WithResolver()) {
var vm = new ActivatingViewModel();
var fixture = new ActivatingView();

Expand All @@ -270,6 +268,87 @@ public void CanUnloadAndLoadViewAgain()
Assert.Equal(1, fixture.IsActiveCount);
}
}
}

public class ViewModelActivatorTests
{
[Fact]
public void ActivatingTicksActivatedObservable()
{
var viewModelActivator = new ViewModelActivator();
var activated = viewModelActivator.Activated.CreateCollection();

viewModelActivator.Activate();

Assert.Equal(1, activated.Count);
}

[Fact]
public void DeactivatingIgnoringRefCountTicksDeactivatedObservable()
{
var viewModelActivator = new ViewModelActivator();
var deactivated = viewModelActivator.Deactivated.CreateCollection();

viewModelActivator.Deactivate(true);

Assert.Equal(1, deactivated.Count);
}

[Fact]
public void DeactivatingCountDoesntTickDeactivatedObservable()
{
var viewModelActivator = new ViewModelActivator();
var deactivated = viewModelActivator.Deactivated.CreateCollection();

viewModelActivator.Deactivate(false);

Assert.Equal(0, deactivated.Count);
}

[Fact]
public void DeactivatingFollowingActivatingTicksDeactivatedObservable()
{
var viewModelActivator = new ViewModelActivator();
var deactivated = viewModelActivator.Deactivated.CreateCollection();

viewModelActivator.Activate();
viewModelActivator.Deactivate(false);

Assert.Equal(1, deactivated.Count);
}
}

public class CanActivateViewFetcherTests
{
private class CanActivateStub : ICanActivate
{
public IObservable<Unit> Activated { get; }

public IObservable<Unit> Deactivated { get; }
}

[Fact]
public void ReturnsPositiveForICanActivate()
{
var canActivateViewFetcher = new CanActivateViewFetcher();
var affinity = canActivateViewFetcher.GetAffinityForView(typeof(ICanActivate));
Assert.True(affinity > 0);
}

[Fact]
public void ReturnsPositiveForICanActivateDerivatives()
{
var canActivateViewFetcher = new CanActivateViewFetcher();
var affinity = canActivateViewFetcher.GetAffinityForView(typeof(CanActivateStub));
Assert.True(affinity > 0);
}

[Fact]
public void ReturnsZeroForNonICanActivateDerivatives()
{
var canActivateViewFetcher = new CanActivateViewFetcher();
var affinity = canActivateViewFetcher.GetAffinityForView(typeof(CanActivateViewFetcherTests));
Assert.Equal(0, affinity);
}
}
}
2 changes: 1 addition & 1 deletion src/ReactiveUI.Tests/ReactiveUI.Tests_Android.csproj
Expand Up @@ -136,7 +136,7 @@
<Compile Include="MainActivity.cs" />
<Compile Include="Resources\Resource.designer.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ActivationTest.cs" />
<Compile Include="ActivationTests.cs" />
<Compile Include="AutoPersistHelperTest.cs" />
<Compile Include="AwaiterTest.cs" />
<Compile Include="BindingTypeConvertersTest.cs" />
Expand Down
2 changes: 1 addition & 1 deletion src/ReactiveUI.Tests/ReactiveUI.Tests_Net45.csproj
Expand Up @@ -97,7 +97,7 @@
</CodeAnalysisDependentAssemblyPaths>
</ItemGroup>
<ItemGroup>
<Compile Include="ActivationTest.cs" />
<Compile Include="ActivationTests.cs" />
<Compile Include="AutoPersistHelperTest.cs" />
<Compile Include="AwaiterTest.cs" />
<Compile Include="BindingTypeConvertersTest.cs" />
Expand Down
2 changes: 1 addition & 1 deletion src/ReactiveUI.Tests/ReactiveUI.Tests_iOS.csproj
Expand Up @@ -170,7 +170,7 @@
<Compile Include="Cocoa\IndexNormalizerTest.cs" />
<Compile Include="Main.cs" />
<Compile Include="AppDelegate.cs" />
<Compile Include="ActivationTest.cs" />
<Compile Include="ActivationTests.cs" />
<Compile Include="AutoPersistHelperTest.cs" />
<Compile Include="AwaiterTest.cs" />
<Compile Include="BindingTypeConvertersTest.cs" />
Expand Down
39 changes: 37 additions & 2 deletions src/ReactiveUI/CommandBinding.cs
Expand Up @@ -9,6 +9,9 @@

namespace ReactiveUI
{
/// <summary>
/// Various helpers to bind View controls and ViewModel commands together
/// </summary>
public static class CommandBinder
{
static ICommandBinderImplementation binderImplementation;
Expand All @@ -30,7 +33,7 @@ static CommandBinder()
/// <param name="view">The View</param>
/// <param name="viewModel">The View model</param>
/// <param name="controlName">The name of the control on the view</param>
/// <param name="propertyName">The ViewModel command to Bind.</param>
/// <param name="propertyName">The ViewModel command to bind.</param>
/// <param name="withParameter">The ViewModel property to pass as the
/// param of the ICommand</param>
/// <param name="toEvent">If specified, bind to the specific event
Expand All @@ -57,6 +60,7 @@ static CommandBinder()
/// the binding</returns>
/// <param name="view">The View</param>
/// <param name="viewModel">The View model</param>
/// <param name="propertyName">The ViewModel command to bind</param>
/// <param name="controlName">The name of the control on the view</param>
/// <param name="toEvent">If specified, bind to the specific event
/// instead of the default.</param>
Expand All @@ -81,6 +85,7 @@ static CommandBinder()
/// the binding</returns>
/// <param name="view">The View</param>
/// <param name="viewModel">The View model</param>
/// <param name="propertyName">The ViewModel command to bind</param>
/// <param name="controlName">The name of the control on the view</param>
/// <param name="withParameter">The ViewModel property to pass as the
/// param of the ICommand</param>
Expand Down Expand Up @@ -126,8 +131,25 @@ interface ICommandBinderImplementation : IEnableLogger
where TProp : ICommand;
}

/// <summary>
/// Used by the CommandBinder extension methods to handle binding View controls and ViewModel commands
/// </summary>
public class CommandBinderImplementation : ICommandBinderImplementation
{
/// <summary>
/// Bind a command from the ViewModel to an explicitly specified control
/// on the View.
/// </summary>
/// <returns>A class representing the binding. Dispose it to disconnect
/// the binding</returns>
/// <param name="view">The View</param>
/// <param name="viewModel">The View model</param>
/// <param name="controlProperty">The name of the control on the view</param>
/// <param name="vmProperty">The ViewModel command to bind</param>
/// <param name="withParameter">The ViewModel property to pass as the
/// param of the ICommand</param>
/// <param name="toEvent">If specified, bind to the specific event
/// instead of the default.</param>
public IReactiveBinding<TView, TViewModel, TProp> BindCommand<TView, TViewModel, TProp, TControl, TParam>(
TViewModel viewModel,
TView view,
Expand Down Expand Up @@ -157,6 +179,20 @@ public class CommandBinderImplementation : ICommandBinderImplementation
source, BindingDirection.OneWay, bindingDisposable);
}

/// <summary>
/// Bind a command from the ViewModel to an explicitly specified control
/// on the View.
/// </summary>
/// <returns>A class representing the binding. Dispose it to disconnect
/// the binding</returns>
/// <param name="view">The View</param>
/// <param name="viewModel">The View model</param>
/// <param name="controlProperty">The name of the control on the view</param>
/// <param name="vmProperty">The ViewModel command to bind</param>
/// <param name="withParameter">The ViewModel property to pass as the
/// param of the ICommand</param>
/// <param name="toEvent">If specified, bind to the specific event
/// instead of the default.</param>
public IReactiveBinding<TView, TViewModel, TProp> BindCommand<TView, TViewModel, TProp, TControl, TParam>(
TViewModel viewModel,
TView view,
Expand Down Expand Up @@ -303,7 +339,6 @@ public static IDisposable BindCommandToObject(ICommand command, object target, I
var mi = binder.GetType().GetTypeInfo().DeclaredMethods.First(x => x.Name == "BindCommandToObject" && x.IsGenericMethod);
mi = mi.MakeGenericMethod(new[] {eventArgsType});

//var ret = binder.BindCommandToObject<TEventArgs>(command, target, commandParameter, eventName);
var ret = (IDisposable) mi.Invoke(binder, new[] {command, target, commandParameter, eventName});
if (ret == null) {
throw new Exception(String.Format("Couldn't bind Command Binder for {0} and event {1}", type.FullName, eventName));
Expand Down
16 changes: 2 additions & 14 deletions src/ReactiveUI/ReactiveBinding.cs
Expand Up @@ -18,7 +18,7 @@ public interface IReactiveBinding<TView, TViewModel, TValue> : IDisposable
where TView : IViewFor
{
/// <summary>
/// The instance of the view model this binding is applied to.</param>
/// The instance of the view model this binding is applied to.
/// </summary>
/// <value>
/// The view model.
Expand Down Expand Up @@ -76,15 +76,6 @@ internal class ReactiveBinding<TView, TViewModel, TValue> : IReactiveBinding<TVi
{
private IDisposable bindingDisposable;

/// <summary>
/// Initializes a new instance of the <see cref="AppliedBindingInfo{TViewModel}" /> class.
/// </summary>
/// <param name="view">The view.</param>
/// <param name="viewModel">The view model.</param>
/// <param name="viewPath">The view path.</param>
/// <param name="viewModelPath">The view model path.</param>
/// <param name="direction">The direction.</param>
/// <param name="bindingDisposable">The binding disposable.</param>
public ReactiveBinding(TView view, TViewModel viewModel, Expression viewExpression, Expression viewModelExpression,
IObservable<TValue> changed, BindingDirection direction, IDisposable bindingDisposable)
{
Expand All @@ -99,7 +90,7 @@ internal class ReactiveBinding<TView, TViewModel, TValue> : IReactiveBinding<TVi
}

/// <summary>
/// The instance of the view model this binding is applied to.</param>
/// The instance of the view model this binding is applied to.
/// </summary>
/// <value>
/// The view model.
Expand Down Expand Up @@ -150,9 +141,6 @@ internal class ReactiveBinding<TView, TViewModel, TValue> : IReactiveBinding<TVi
/// </value>
public BindingDirection Direction { get; private set; }

/// <summary>
/// Releases unmanaged and - optionally - managed resources.
/// </summary>
public void Dispose()
{
if (bindingDisposable != null) {
Expand Down

0 comments on commit 3300405

Please sign in to comment.