MvvmCross - How to get iOS Views to load from a di

2019-09-17 10:31发布

问题:

I am trying to get the Views in my xamarin-forms + mvvmcross project to load correctly with no luck.

Project structure breakdown:

Project: Shared.Core - 100% cross platform code, view models, models, etc..

Project: Shared.Mobile - Xamarin-forms views

Project: iOS - uses shared views

Project: Android - uses shared views

Project: UWP - uses shared views

Project: WPF - uses WPF native views

I have a working WPF project using mvvmcross and am trying to get the mobile going starting with iOS.

The iOS project is only loading the views when the views and viewmodels are in the same assembly. Otherwise I am getting:

Foundation.MonoTouchException: Objective-C exception thrown. Name: NSInternalInconsistencyException Reason: Application windows are expected to have a root view controller at the end of application launch

The same can be seen from this sample project by taking the PCL Views folder and moving it to the iOS project.

https://github.com/MvvmCross/MvvmCross-Forms/tree/master/Samples/Example001XAML

I have also tried the following to no avail:

Setup.cs

protected override IEnumerable<Assembly> GetViewModelAssemblies()
{
    var result = base.GetViewModelAssemblies();
    var assemblyList = result.ToList();
    assemblyList.Add(typeof(FirstViewModel).Assembly);
    return assemblyList.ToArray();
}

protected override IEnumerable<Assembly> GetViewAssemblies()
{
    var result = base.GetViewAssemblies();
    var assemblyList = result.ToList();
    assemblyList.Add(typeof(FirstPage).Assembly);
    return assemblyList.ToArray();
}

protected override void InitializeViewLookup()
{
    base.InitializeViewLookup();

    var vmLookup = new Dictionary<Type, Type> {
        {typeof (FirstViewModel), typeof (FirstPage)},
        {typeof (AboutViewModel), typeof (AboutPage)}
    };

    var container = Mvx.Resolve<IMvxViewsContainer>();
    container.AddAll(vmLookup);
}

回答1:

I have just fixed this in the Forms presenter core so it now works! You were on the right track with overriding GetViewsAssemblies or InitializeViewLookup. That is how it should work if the presenter had been implemented correctly to begin with.

Anyways, with the new changes in this Pull Request the way it works is:

Either override GetViewsAssemblies to let InitializeViewLookup internally map Views to ViewModels, from the found views in where you tell MvvmCross to look for them. The code in Setup.cs will look something like:

protected override IEnumerable<Assembly> GetViewAssemblies()
{
    var result = base.GetViewAssemblies();
    var assemblyList = result.ToList();
    assemblyList.Add(typeof(FirstPage).Assembly);
    return assemblyList;
}

Where FirstPage is one of the pages in an Assembly containing views.

Or you can explicitly tell MvvmCross how to map Views to ViewModels in InitializeViewLookup:

protected override void InitializeViewLookup()
{
    base.InitializeViewLookup();

    var vmLookup = new Dictionary<Type, Type> {
        {typeof (FirstViewModel), typeof (FirstPage)}
    };

    var container = Mvx.Resolve<IMvxViewsContainer>();
    container.AddAll(vmLookup);
}