Scenario: I need to create and load fragments dynamically (by code).
Example: I have a hierarchical data with categories and items, a category can contain items and other categories, like in Windows Explorer:

When user clicks on a folder icon, if it’s a folder, it will show the same view with folder’s child folders and items. If it’s an icon, we want to show just a label with the name of the item (in real-life, this can be rendering a document).
In Android, we will need
- an activity class and layout (or even a parent fragment) as host for the views. it will create and show the fragments dynamically by code,
- a fragment class and layout for the folder view (with a GridView)
- a fragment class and layout for the item view (with a TextView)
With MVVMCross, we will also have:
- a view-model class for the activity/parent fragment host
- a view-model class for the folder view
- a view-model class for the item view
With MVVM, when user clicks on a folder icon, the view-model is responsible to handle the event (by a Command) and trigger navigation to another fragment view, depending on the icon. But remember that the view-model must NOT directly instantiate and show the views, this is platform specific UI code.
In MVVMCross, we call MvxViewModel.ShowViewModel method to‘show’ the view-model. By default, what happens is, the MVVMCross finds the associated activity class (based on a name convention) and shows it. But In our case, this won’t work, because the view-models refer to fragments.
The solution is to use MVVMCross features to control the view creation mechanism.
MVVMCross has a built-in MvxAndroidViewPresenter class used to create and show an activity based on the view-model:
public class MvxAndroidViewPresenter : IMvxAndroidViewPresenter, IMvxViewPresenter
{
public virtual void Show (MvxViewModelRequest request)
{
IMvxAndroidViewModelRequestTranslator mvxAndroidViewModelRequestTranslator = Mvx.Resolve<IMvxAndroidViewModelRequestTranslator> ();
Intent intentFor = mvxAndroidViewModelRequestTranslator.GetIntentFor (request);
this.Activity.StartActivity (intentFor);
}
}
We can tell MVVMCross to use instead our own view presenter implementation which creates and shows fragments inside our activity or parent fragment.
public class CustomPresenter : MvxAndroidViewPresenter, ICustomPresenter
{
private Dictionary<Type, IFragmentHost> dictionary = new Dictionary<Type, IFragmentHost>();
public override void Show(MvxViewModelRequest request)
{
IFragmentHost host;
if (this.dictionary.TryGetValue(request.ViewModelType, out host))
{
if (host.Show(request))
{
return;
}
}
base.Show(request);
}
public void Register(Type viewModelType, IFragmentHost host)
{
this.dictionary[viewModelType] = host;
}
}
The class is responsible for keeping a mapping between view-model types and the hosts which will instantiate and show the fragments.
We can now can register it for MVVMCross to use it, this being done in the Setup class in the Android app:
public class Setup : MvxAndroidSetup
{
protected override IMvxAndroidViewPresenter CreateViewPresenter()
{
var customPresenter = new CustomPresenter();
Mvx.RegisterSingleton<ICustomPresenter>(customPresenter);
return customPresenter;
}
}
Note that the custom presenter once registered in MVVMCross, will be called for ANY view-model, whenever we call MvvmViewModel : ShowViewModel<T>();
ICustomPresenter and IFragmentHost are some simple interfaces we define in our code in order to nicely decouple the MVVMCross custom view presenter from the fragment host:
public interface ICustomPresenter
{
void Register(Type viewModelType, IFragmentHost host);
}
public interface IFragmentHost
{
bool Show(MvxViewModelRequest request);
}
It makes sense for the activity class to implement the IFragmentHost interface:
public class MainView: MvxFragmentActivity, IFragmentHost
{
public bool Show(Cirrious.MvvmCross.ViewModelsMvxViewModelRequest request)
{
var loaderService = Mvx.Resolve<IMvxViewModelLoader> ();
var viewModel = loaderService.LoadViewModel (request, null );
var fragmentView = ...
var ft = fragmentManager.BeginTransaction ();
ft.Replace (Resource.Id.fragmentHost, fragmentView);
ft.AddToBackStack (null);
ft.Commit ();
}
}
Further more, we can have the activity have its own dictionary to keep a mapping between view-models and fragments, such that we can instantiate fragments based on the view-model class:
private Dictionary<Type, Type> vmTypeFragmentTypeDictionary = new Dictionary<Type, Type>();
public bool ShowFragment(FragmentManager fragmentManager, MvxViewModelRequest request, bool addToBackstack)
{
Type fragmentType;
if (vmTypeFragmentTypeDictionary.TryGetValue (request.ViewModelType, out fragmentType)) {
var loaderService = Mvx.Resolve<IMvxViewModelLoader> ();
var viewModel = loaderService.LoadViewModel (request, null );
var fragmentView = Activator.CreateInstance (fragmentType) as MvxFragment;
fragmentView.ViewModel = viewModel;
var ft = fragmentManager.BeginTransaction ();
ft.Replace (Resource.Id.fragmentHost, fragmentView);
if (addToBackstack) {
ft.AddToBackStack (null);
}
ft.Commit ();
return true;
}
else {
return false;
}
}
public void Register(Type viewModelType, Type fragmentType)
{
vmTypeFragmentTypeDictionary[viewModelType] = fragmentType;
}
To make it reusable, we can even create a base class with this code, called for example MvxActivityFragmentHost and have the activity derive from it:
public class MvxActivityFragmentHost : MvxFragment, IFragmentHost
{
...
}
public class MainView : MvxActivityFragmentHost
{
....
}