Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

create or inject ViewModel when building a "tabs" application

We try to build an application with a few tabs. As reference-project we use that example: http://slodge.blogspot.co.uk/2013/06/n25-tabs-n1-days-of-mvvmcross.html

To get the ViewModel-instances we need to create the tabs, we used the "HomeViewModel"-pattern as mentioned in that post: Create View Model using MVVMCross built in factory?

What I don't like at this approach is the initialisation of ViewModel's with "new". As far as I understand, it skips the whole ViewModel-Lifecycle (https://github.com/slodge/MvvmCross/wiki/View-Model-Lifecycle) which we really like. In our current project, we'd like to use the "start()" lifecycle-method, but it's never called due to initialisation with "new".

What worked for us was to go that way:

var loaderService = Mvx.Resolve<IMvxViewModelLoader>(); 
var vm = (UserListViewModel)loaderService.LoadViewModel(new MvxViewModelRequest(typeof(UserListViewModel), null, null, null), null);

So my question: Is that the way to do the job or is it just a dirty workaround and there is a much better solution?

Update: We came to that solution:

CreateTabFor<SettingsViewModel>("Settings", "settings");
//This method loads the ViewModel
private UIViewController CreateTabFor<TTargetViewModel>(string title, string imageName)  
    where TTargetViewModel : class, IMvxViewModel
{
    var controller = new UINavigationController();
    controller.NavigationBar.TintColor = UIColor.Black;

    var viewModelRequest = new MvxViewModelRequest(typeof(TTargetViewModel), null, null, null);
    var screen = this.CreateViewControllerFor<TTargetViewModel>(viewModelRequest) as UIViewController;
    SetTitleAndTabBarItem(screen, title, imageName);
    controller.PushViewController(screen, false);
    return controller;
}
like image 314
Ursin Brunner Avatar asked Jul 18 '13 09:07

Ursin Brunner


1 Answers

The 'viewmodel lifecycle' is an area of conflicting interests in MvvmCross. The root cause is the conflict between:

  • viewmodel's which are just the models for any view
  • viewmodel's which are specifically used within the 'ShowViewModel' navigation process

For simple 'whole page' User Experiences, the C-I-R-S viewmodel lifecycle is easy to support and to ensure it gets consistently used.

However, as soon as the user experience starts to merge in tabs, flyouts, hamburger menus, dialogs, split views, etc then:

  1. the developers sometimes want to control viewmodel lifecycles themselves
  2. it's not as easy for the framework to ensure that view models are always created, activated and tombstoned/rehydrated consistently

Personally, I like your approach - of trying to ensure all viewmodels are independent and all constructed the same way - but MvvmCross doesn't force this approach on all developers.

Specifically for tabs, most of the existing examples do use the 'owned sub-viewmodel' pattern that you've identified.

However, it should be relatively easy to implement other mechanisms if you want to - just as you already have.

In particular, you can:

  • use the loaderService directly - getting hold of it via Mvx.Resolve<IMvxViewModelLoader>();
  • use ShowViewModel with a custom presenter to create both views and viewmodels - the beginnings of this is illustrated in that N=25 video but you could take it much further and actually add the tabs in response to ShowViewModel calls.
  • use alternative calls to create the child tabs and their viewmodels inside the Views - e.g. where the Touch sample currently calls

       var screen = this.CreateViewControllerFor(viewModel) as UIViewController;
    

    this could easily be replace with something like:

       var screen = this.CreateViewControllerFor<ChildViewModel>() as UIViewController;;
    

    (or one of the other overloads from MvxCanCreateIosViewExtensionMethods.cs)

One repo where I know some users have taken some of these ideas and played with them is the Sliding menu repo - I think they have chosen to use this.CreateViewControllerFor<TViewModel> to create their view models. This may or may not be the way you choose to go - but it might be of interest for you to experiment with.

like image 118
Stuart Avatar answered Nov 01 '22 15:11

Stuart