简体   繁体   中英

MVVMCross: Is it possible to use Storyboard with ICommand navigation?

I've spent the last few days trying to figure out a way to get around the warning:

mvx: Warning: 8.93 Exception masked MissingMethodException: Default constructor not found for type FCX.iOS.TimesheetView at System.Activator.CreateInstance (System.Type type, Boolean nonPublic) [0x00094] in /Developer/MonoTouch/Source/mono/mcs/class/corlib/System/Activator.cs:326 at System.Activator.CreateInstance (System.Type type) [0x00000] in /Developer/MonoTouch/Source/mono/mcs/class/corlib/System/Activator.cs:222 at Cirrious.MvvmCross.Touch.Views.MvxTouchViewsContainer.CreateView (Cirrious.MvvmCross.ViewModels.MvxViewModelRequest request) [0x00000] in :0 at Cirrious.MvvmCross.Touch.Views.MvxCanCreateTouchViewExtensionMethods.CreateViewControllerFor (IMvxCanCreateTouchView view, Cirrious.MvvmCross.ViewModels.MvxViewModelRequest request) [0x00000] in :0 at Cirrious .MvvmCross.Touch.Views.Presenters.MvxTouchViewPresenter.Show (Cirrious.MvvmCross.ViewModels.MvxViewModelRequest request) [0x00000] in :0 at Cirrious.MvvmCross.Touch.Views.MvxTouchViewDispatcher+<>c__DisplayClass4.b__3 () [0x00000] in :0 at Cirrious.CrossCore.Core.MvxMainThreadDispatcher.ExceptionMaskedAction (System.Action action) [0x00000] in :0

It appears the navigation is looking for this constructor:

    public TimesheetView ()
    {
    }

When I WANT it to use this constructor (for storyboard purposes):

    public TimesheetView (IntPtr handle) : base (handle)
    {
    }

I've been trying to bind a button from one view to the following ICommand:

    private MvxCommand _NewTimesheetCommand;
    public ICommand NewTimesheetCommand
    {
        get
        {
            _NewTimesheetCommand =  _NewTimesheetCommand ?? new MvxCommand(() => {
                ShowViewModel<TimesheetViewModel>(new TimesheetViewModel.Parameters { Mode = TimesheetViewModel.ModeEnum.ADD });
            });
            return _NewTimesheetCommand;
        }
    }

After looking at many StackOverFlow questions, I came across this question, but it almost sounds that using storyboards REQUIRES me to use segues (in other words there isn't a way to use ICommand to change my view).

Does MvvmCross support storyboards

My main question: Is it possible to use storyboards and change the view with the viewmodel? (rather than using segues from the view)

Hmmm I just implemented what Stuart said. Works great. (Do remember that segue's are useless this way you navigate using ShowViewModel inside the viewmodels)

using System;
using Cirrious.MvvmCross.Touch.Views.Presenters;
using MonoTouch.UIKit;
using MonoTouch.Foundation;     
using Cirrious.MvvmCross.Touch.Views;
using Cirrious.MvvmCross.ViewModels;

 namespace DigitalCatalog.UI.Touch
 {
   public class StoryBoardTouchViewPresenter : MvxTouchViewPresenter
  {
    public static UIStoryboard Storyboard = null;


    public StoryBoardTouchViewPresenter (UIApplicationDelegate applicationDelegate, UIWindow window, string storyboardName, NSBundle StoryboardBundleOrNull = null) : base(applicationDelegate, window)
    {
        Storyboard = UIStoryboard.FromName (storyboardName, StoryboardBundleOrNull);
    }

    public override void Show (IMvxTouchView view)
    {
        MvxViewController sbView = null;

        try{
            sbView = (MvxViewController) Storyboard.InstantiateViewController (view.Request.ViewModelType.Name.Replace("Model", ""));
        }catch(Exception e){
            Console.WriteLine ("Failed to find storyboard view, did you forget to set the Storyboard ID to the ViewModel class name without the Model suffix ?" + e);
        }

        sbView.Request = view.Request;

        base.Show (sbView);
    }

}
 }

All you have to do now is set the AppDelegate like this :

public override void FinishedLaunching (UIApplication application)
    {


        StoryBoardTouchViewPresenter sbPresenter = new StoryBoardTouchViewPresenter(this, Window,"MainStoryboard_iPad");


        var setup = new Setup(this,sbPresenter);
        setup.Initialize();

        var startup = Mvx.Resolve<IMvxAppStart>();
        startup.Start();


        sbPresenter.MasterNavigationController.NavigationBar.Translucent = false;

        sbPresenter.MasterNavigationController.SetNavigationBarHidden(false, false);

    }

LAST REMEMBER TO SET FOR EVERY VIEW IN THE STORYBOARD A STORYBOARD ID WITH THE "CLASS NAME" OF THE VIEW !!!! sadly there isn't any other way to get a view using the UIStoryboard class you can only get it by using Storyboard Ids

There are ways to load a `UiViewController. From a storyboard - eg see load view form StoryBoard that does not have a Segue

If you want to use this custom loading in mvvmcross, then you could override the IMvxTouchViewCreator so that it uses this sort of storyboard load, or you could override the presenter so that it loads the storyboard view directly .

Overall, though, it feels like you are fighting against storyboards if you are working this way - almost all storyboard navigation seems to be segue based. With this in mind another thing you could do is to implement a custom presenter and to get that presenter to convert ShowViewModel requests into performSegueWithIdentifier calls.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM