Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions ReactiveUI.Tests/RxRouting.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,14 @@ public BazViewModel(IScreen hostScreen)
HostScreen = hostScreen;
}
}

[ViewResolutionTypeOverride(Type = typeof(BazViewModel))]
public class BazViewModel<T> : BazViewModel
{
public BazViewModel(IScreen hostScreen) : base(hostScreen)
{
}
}
}

namespace Foobar.Views
Expand Down Expand Up @@ -80,5 +88,25 @@ public void ResolveExplicitViewType()
Assert.True(result is BazView);
}
}

[Fact]
public void ResolveViewForGenericViewModelType()
{
var resolver = new ModernDependencyResolver();

resolver.InitializeSplat();
resolver.InitializeReactiveUI();
resolver.Register(() => new BazView(), typeof(IViewFor<BazViewModel>));

using (resolver.WithResolver())
{
var fixture = new DefaultViewLocator();
var vm = new BazViewModel<int>(null);

var result = fixture.ResolveView(vm);
this.Log().Info(result.GetType().FullName);
Assert.True(result is BazView);
}
}
}
}
14 changes: 14 additions & 0 deletions ReactiveUI/Interfaces.cs
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,20 @@ public class ViewContractAttribute : Attribute
/// </summary>
public string Contract { get; set; }
}

/// <summary>
/// Allows overriding the type information used for view resolution of a view
/// model. This is useful if your view model is a generic type and you would
/// prefer to resolve your view using an interface.
/// </summary>
public class ViewResolutionTypeOverrideAttribute : Attribute
{
/// <summary>
/// The type that will be used in view resolution instead of the owning
/// view model type
/// </summary>
public Type Type { get; set; }
}
}

// vim: tw=120 ts=4 sw=4 et :
14 changes: 11 additions & 3 deletions ReactiveUI/ViewLocator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,21 +50,29 @@ public IViewFor ResolveView<T>(T viewModel, string contract = null)
// * IViewFor<IFooBarViewModel>
// * IViewFor<FooBarViewModel> (the original behavior in RxUI 3.1)

var attrs = viewModel.GetType().GetTypeInfo().GetCustomAttributes(typeof (ViewContractAttribute), true);
var viewModelType = viewModel.GetType();

var attrs = viewModelType.GetTypeInfo().GetCustomAttributes(typeof(ViewContractAttribute), true);

if (attrs.Any()) {
contract = contract ?? ((ViewContractAttribute) attrs.First()).Contract;
}

attrs = viewModelType.GetTypeInfo().GetCustomAttributes(typeof(ViewResolutionTypeOverrideAttribute), true);

if (attrs.Any()) {
viewModelType = ((ViewResolutionTypeOverrideAttribute)attrs.First()).Type;
}

// IFooBarView that implements IViewFor (or custom ViewModelToViewFunc)
var typeToFind = ViewModelToViewFunc(viewModel.GetType().AssemblyQualifiedName);
var typeToFind = ViewModelToViewFunc(viewModelType.AssemblyQualifiedName);

var ret = attemptToResolveView(Reflection.ReallyFindType(typeToFind, false), contract);
if (ret != null) return ret;

// IViewFor<FooBarViewModel> (the original behavior in RxUI 3.1)
var viewType = typeof (IViewFor<>);
return attemptToResolveView(viewType.MakeGenericType(viewModel.GetType()), contract);
return attemptToResolveView(viewType.MakeGenericType(viewModelType), contract);
}

IViewFor attemptToResolveView(Type type, string contract)
Expand Down