LoginSignup
5
5

More than 5 years have passed since last update.

Xamarin.iOSでMvvmCrossとStoryboardを使っている時にShowViewModelを動作させるためにやったこと

Last updated at Posted at 2014-06-09

StoryboardとMvvmCrossをうまく同居させるときに色々苦労したのでここにメモります
Xamarin.Formsが出たのでちょっと旬が過ぎた気はしますが、需要はあるかなと

Storyboardを使っているときにMvvmCrossのShowViewModelが使えなかったので
ここではそれをどう直したかについてメモを書いていきます

やり方はMvxTouchViewPresentatorとMvxTouchViewsContainerの2つを継承し、既存のクラスを置き換えることで解決します。

  • MvxTouchViewPresentatorを継承したクラスを作成し、RootViewControllerをMasterNavigationControllerに代入する
    public class CustomTouchViewPresenter : MvxTouchViewPresenter
    {

        public CustomTouchViewPresenter(UIApplicationDelegate applicationDelegate, UIWindow window) : base(applicationDelegate, window)
        {
            var uiNavigationController = window.RootViewController as UINavigationController;
            if (uiNavigationController != null)
                this.MasterNavigationController = uiNavigationController;
        }

    }
  • MvxTouchViewControllerをstoryboard対応のために以下のように拡張する
    public class MvxStoryboardTouchViewsContainer : MvxTouchViewsContainer
    {
        const string ViewModelSuffix = "ViewModel";
        const string ControllerSuffix = "Controller";
        UIStoryboard _storyboard;
        public MvxStoryboardTouchViewsContainer(string storyboardName)
        {
            _storyboard = UIStoryboard.FromName(storyboardName, null);
        }
        public override IMvxTouchView CreateView(Cirrious.MvvmCross.ViewModels.MvxViewModelRequest request)
        {
            var view = CreateViewFromViewModelType(request.ViewModelType);
            if(view == null)
            {
                var viewType = GetViewType(request.ViewModelType);
                if (viewType == null)
                    throw new MvxException("View Type not found for " + request.ViewModelType);

                view = CreateViewOfType(viewType, request);
            }
            view.Request = request;
            return view;
        }
        protected override IMvxTouchView CreateViewOfType(Type viewType, Cirrious.MvvmCross.ViewModels.MvxViewModelRequest request)
        {
            return CreateView(viewType.Name);
        }

        IMvxTouchView CreateViewFromViewModelType(Type viewModelType)
        {
            var name = viewModelType.Name;
            if (name.EndsWith(ViewModelSuffix))
            {
                name = name.Substring(0, name.Length - ViewModelSuffix.Length) + ControllerSuffix;
            }
            return CreateView(name);
        }

        IMvxTouchView CreateView(string viewName)
        {

            return (IMvxTouchView)_storyboard.InstantiateViewController(viewName);
        }
    }

  • SetupクラスとAppDelegateを以下のように置き換える
    public class Setup : MvxTouchSetup
    {
        public Setup(MvxApplicationDelegate appDelegate, IMvxTouchViewPresenter presenter)
            : base(appDelegate, presenter) { }

        protected override IMvxApplication CreateApp()
        {
            return new MyApp();
        }
        protected override Cirrious.MvvmCross.Touch.Views.IMvxTouchViewsContainer CreateTouchViewsContainer()
        {
            return new MvxStoryboardTouchViewsContainer("MainStoryboard");
        }

    }

    [Register ("AppDelegate")]
    public partial class AppDelegate : MvxApplicationDelegate
    {
        // class-level declarations
        public override UIWindow Window {
            get;
            set;
        }
        // This method is invoked when the application is about to move from active to inactive state.
        // OpenGL applications should use this method to pause.
        public override void OnResignActivation (UIApplication application)
        {
        }
        // This method should be used to release shared resources and it should store the application state.
        // If your application supports background exection this method is called instead of WillTerminate
        // when the user quits.
        public override void DidEnterBackground (UIApplication application)
        {
        }
        // This method is called as part of the transiton from background to active state.
        public override void WillEnterForeground (UIApplication application)
        {
        }
        // This method is called when the application is about to terminate. Save data, if needed.
        public override void WillTerminate (UIApplication application)
        {
        }

        public override void FinishedLaunching(UIApplication application)
        {
            var setup = new Setup(this, new CustomTouchViewPresenter(this, Window));
            setup.Initialize();
        }
    }

  • Storyboard Idとクラス名を以下のように修正する

○○ViewModelに対応するControllerのStoryboard Idを○○Controllerに指定する

以上です。

動作原理

  • MvxTouchViewsContainerでControllerの解決を行っているのでStoryboardから取得するように修正。その際、ViewModelのクラス名からStoryboard Idを取得
  • Storyboardだと、正しくNavigationControllerが認識されないので、Presentatorを継承してコンストラクタでRootViewControllerから取得して代入
5
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
5