How to Use Different ViewModels

How to Use Different ViewModels for Different Platforms

The start viewmodel type can be selected through App initialization. For instance, it can help when we have to match the navigation system adopted for the current platform.

There are exists PlatformType class. It defines constants for all supported platforms.

public class PlatformType : StringConstantBase<PlatformType>
{
  public static readonly PlatformType Android;
  public static readonly PlatformType iOS;
  public static readonly PlatformType WinForms;
  public static readonly PlatformType UWP;
  public static readonly PlatformType UWPPhone;
  public static readonly PlatformType WPF;
  public static readonly PlatformType Unknown;
  public static readonly PlatformType UnitTest;
  public static readonly PlatformType XamarinFormsAndroid;
  public static readonly PlatformType XamarinFormsiOS;
  public static readonly PlatformType XamarinFormsWinPhone;
  public static readonly PlatformType XamarinFormsWinRT;
  public static readonly PlatformType XamarinFormsWinRTPhone;
  public static readonly PlatformType XamarinFormsUWPPhone;
  public static readonly PlatformType XamarinFormsUWP;

  static PlatformType()
  {
    Android = new PlatformType(nameof(Android));
    iOS = new PlatformType(nameof(iOS));
    WinForms = new PlatformType(nameof(WinForms));
    UWP = new PlatformType(nameof(UWP));
    UWPPhone = new PlatformType(nameof(UWPPhone));
    WPF = new PlatformType(nameof(WPF));
    XamarinFormsAndroid = new PlatformType(nameof(XamarinFormsAndroid));
    XamarinFormsiOS = new PlatformType(nameof(XamarinFormsiOS));
    XamarinFormsWinPhone = new PlatformType(nameof(XamarinFormsWinPhone));
    XamarinFormsWinRT = new PlatformType(nameof(XamarinFormsWinRT));
    XamarinFormsWinRTPhone = new PlatformType(nameof(XamarinFormsWinRTPhone));
    XamarinFormsUWP = new PlatformType(nameof(XamarinFormsUWP));
    XamarinFormsUWPPhone = new PlatformType(nameof(XamarinFormsUWPPhone));
    Unknown = new PlatformType("Unknown");
    UnitTest = new PlatformType("UnitTest");
  }

  public PlatformType(string id) : base(id) { }
}

Current platform type can be checked by Platform property of MvvmApplication.

Let's see an example. Suppose we want to use different start viewmodel for iOS and Android. Just override GetStartViewModelType of MvvmApplication:

public class App : MvvmApplication
{
  public App()
  {
  }

  public override Type GetStartViewModelType()
  {    
    var platformType = Platform.Platform;
    if (platformType == PlatformType.Android)
    {      
        return typeof(BackStackMainViewModel);      
    }
    else if (platformType == PlatformType.iOS)
    {
      return typeof(SelectedItemMainViewModel);
    }
    return typeof(MainViewModel);
  }
}

Here we just check Platform.Platform property of App and select appropriate viewmodel.

How to Use Different ViewModels for Phone/Tablet

The same idea can be applied when you want to change viewmodel depends on user interface idioms (phone/tablet).

Let's see on iOS example. Suppose that we have module then we can check current device idiom and load appropriate viewmodel:

public class MyModule : IModule
{
    public int Priority { get; } = 0;

    public bool Load(IModuleContext context)
    {
        var viewModelPresenter = context.IocContainer.Get<IViewModelPresenter>();
        if (UIDevice.CurrentDevice.UserInterfaceIdiom == UIUserInterfaceIdiom.Pad)
        {
            viewModelPresenter.DynamicPresenters.Add(new MyTabletPresenter());
        }
        else
        {
            viewModelPresenter.DynamicPresenters.Add(new MyPhonePresenter());
        }

        return true;
    }

    public void Unload(IModuleContext context)
    {
    }
}

In Load method we check current user interface idiom and add appropriate presenter in collection of presenters.

Also you can another approach that uses Bind. Presented below is an example:

public class MyModule : IModule
{
  public int Priority { get; } = 0;

  public bool Load(IModuleContext context)
  {
    var viewModelPresenter = context.IocContainer.Get<IViewModelPresenter>();
    if (UIDevice.CurrentDevice.UserInterfaceIdiom == UIUserInterfaceIdiom.Pad)
    {
      context.IocContainer
        .Bind<MyViewModel, MyPadViewModel>(DependencyLifecycle.SingleInstance);
    }

    return true;
  }

  public void Unload(IModuleContext context)
  {
  }
}