Не удается зарегистрировать View и ViewModel между двумя сборками (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. Вот структура...

введите здесь описание изображения


person Maximus    schedule 11.12.2017    source источник


Ответы (1)


Я столкнулся с той же проблемой в среде, аналогичной вашей. Проблема заключалась в DefaultViewLocator, так как представление type переименовывается и неправильно разрешается в сборку и пространство имен модели представления. См. строки 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));
person dpnolte    schedule 19.12.2017
comment
Ух ты! Я удивлен, что эта ошибка все еще существует в последней версии. Спасибо за ответ!! - person Maximus; 20.12.2017
comment
Кстати, вы повторно использовали существующий код Splat и изменили части выше или полностью переписали этот раздел? - person Maximus; 20.12.2017
comment
Я повторно использовал существующий код и изменил только указанные выше части. - person dpnolte; 20.12.2017