Search code examples
iosxamarinmvvmcross

MvvmCross - View not loaded


I upgraded an old project to Xamarin.iOS Unified and MvvmCross 4.1.

When I run the app, I get the following exception:

MvvmCross.Platform.Exceptions.MvxException: View not loaded for MyView

My classes look like:

MyView : MvxViewController<MyViewModel> {}

MvxViewController<T> : UIViewController, IMvxBindingContextOwner, IUIWrappable 
    where T : ViewModelBase

ViewModelBase : MvxViewModel {}

I suspect I'm missing an interface or something on MyView to enable MvvmCross to operate correctly but I'm not sure what interface this might be.

I suspect this because I already had to hard code in mappings between the View and it's ViewModel, to enable MvvmCross to find the ViewModel through reflection/auto-discovery associated with MyView. That is, before this error, I was getting an unable to find associated ViewModel error.

If I make MyView implement IMvxIosView, this error goes away, and I then get a null reference on the ViewModel later on in my code, so somewhere that is not getting instantiated where it needs to. My impression was this should all be handled automatically by MvvmCross, but I might be wrong.

I'm looking at samples such as https://github.com/MvvmCross/MvvmCross/wiki/Tip-Calc-A-Xamarin.iOS-UI-project

where TipView contains

public new TipViewModel ViewModel {
    get { return (TipViewModel) base.ViewModel; }
    set { base.ViewModel = value; }
}

MyView's base has no such ViewModel property. What am I missing to have access to this?

TipCalc's sample code is still referencing the Cirrious namespace, so it's possible things have changed.

Any suggestions are appreciated. I'm new to Xamarin and MvvmCross (although experienced in Windows/iOS development), and I'm having trouble finding up to date documentation.


Solution

  • Try doing this:

        var vc = this.CreateViewControllerFor(MvxViewModelRequest.GetDefaultRequest(viewModelType);) as MvxViewController;
        vc.OnViewCreate();
    

    The vc.OnViewCreate(); should ensure your View is loaded.

    And the line: this.CreateViewControllerFor(MvxViewModelRequest.GetDefaultRequest(viewModelType);) as MvxViewController;

    Should make sure that the ViewController is created with the ViewModel already set. That way you don't have to set it manually.

    That method is an extension method defined in the MvxCanCreateIosViewExtensionMethods class https://github.com/MvvmCross/MvvmCross/blob/4.0/MvvmCross/iOS/iOS/Views/MvxCanCreateIosViewExtensionMethods.cs

    -- Edit --

    Another thing I noticed in your sample code is this line:

    MyView : MvxViewController<MyView> {}
    

    The type parameter passed into MvxViewController<T> should be the associated ViewModel for MyView, not MyView itself. So for example, you might have something like:

    MyViewModel : ViewModelBase {}
    

    and then:

    MyView : MvxViewController<MyViewModel> {}
    

    -- UPDATE --

    You should be inheriting from the existing MvxViewController provided with MvvmCross. https://github.com/MvvmCross/MvvmCross/blob/3c735adc534a5df2d4730e9d58a08f7863c30cee/MvvmCross/iOS/iOS/Views/MvxViewController.cs