Не удается зарегистрировать View и ViewModel между 2 сборками (UWP, Splat)
Используя последний предварительный просмотр RxUI v8 и Splat 2.0, в проекте UWP, который ссылается на библиотеку.Net Standard 2.0, я не могу зарегистрировать свое представление и модель представления, если они не находятся в одной сборке.
Я имею:
Locator.CurrentMutable.RegisterLazySingleton(() => new HomeView(), typeof(IViewFor<HomeViewModel>));
Но Сплат выдает ошибку:
DefaultViewLocator: Failed to find type named 'RxUI.UWP.Core.Views.HomeView, RxUI.UWP.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'.
DefaultViewLocator: Failed to resolve service for type 'ReactiveUI.IViewFor`1[[RxUI.UWP.Core.ViewModels.HomeViewModel, RxUI.UWP.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]'.
DefaultViewLocator: Failed to find type named 'ReactiveUI.IRoutableView, ReactiveUI, Version=8.0.0.0, Culture=neutral, PublicKeyToken=null'.
DefaultViewLocator: Failed to resolve service for type 'ReactiveUI.IViewFor`1[[ReactiveUI.IRoutableViewModel, ReactiveUI, Version=8.0.0.0, Culture=neutral, PublicKeyToken=null]]'.
DefaultViewLocator: Failed to resolve view for view model type 'ReactiveUI.IRoutableViewModel'.
DefaultViewLocator: Failed to find type named 'RxUI.UWP.Core.Views.HomeView, RxUI.UWP.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'.
Поэтому он ищет HomeView в сборке "Core", но он находится в проекте UWP. Вот структура...
1 ответ
Я столкнулся с той же проблемой, что и ваша среда. Проблема находилась в DefaultViewLocator, поскольку тип представления переименовывается и неправильно разрешается в сборке и пространстве имен модели представления. См. Строки 133-134, как определить имя типа представления:
var viewModelTypeName = viewModelType.AssemblyQualifiedName;
var proposedViewTypeName = this.ViewModelToViewFunc(viewModelTypeName);
Примечание: ViewModelToViewFunc является только String.Replace, который заменяет "ViewModel" на "View" (см. Конструктор).
Чтобы решить эту проблему, я должен был создать собственную реализацию IViewLocator, что-то вроде:
public class MyViewLocator : IViewLocator {
public MyViewModelLocator(Assembly viewAssembly, string viewNameSpace)
...
private IViewFor AttemptViewResolutionFor(Type viewModelType, string contract)
{
// proposed view type is now based on provided namespace + classname as modified by ViewModelToViewFunc
if (viewModelType == null) return null;
var viewModelTypeName = viewModelType.Name;
var proposedViewTypeName = _viewNamespace + "." + this.ViewModelToViewFunc(viewModelTypeName);
...
private IViewFor AttemptViewResolution(string viewTypeName, string contract)
{
try
{
// resolve view type in the assembly of the view, and not assembly of the viewmodel
var viewType = _viewAssembly.GetType(viewTypeName); // instead of Reflection.ReallyFindType(viewTypeName, throwOnFailure: false);
...
}
Наконец, ваша пользовательская реализация viewlocator должна быть зарегистрирована с помощью splat, чтобы она перезаписывала реализацию DefaultViewLocator:
Locator.CurrentMutable.RegisterConstant<IViewLocator>(new MyViewLocator(typeof(SplashView).Namespace, typeof(SplashView).Assembly));