Feature Overview

A typical MugenMVVM application consists of two main layers:

  • core - this layer contains the viewmodels, services and models;
  • UI - this layer contains platform specific views, code and actively interacts with the "core" layer.

A multi-platform application differs from single-platform one by a number of UI layers.
However, other approaches are also possible. For instance, a project where both layers are united in one or a project that consists of several core projects.

Some Important Concepts Within a Typical Application

There are a few key objects within a typical MugenMVVM application:

  • the "core" layer consists of:

    • App class - an application object that implements the IMvvmApplication interface - typically in App.cs;
    • at least one viewmodel - each viewmodel is responsible for a piece of user interaction with your models or services;
    • your services, models and 'business' code.
  • the UI layer consists of:

    • MugenMVVM Setup class - this class is the "bootstraper" for your UI and inherits from the platform specific BootstrapperBase class (AndroidBootstrapperBase, TouchBootstrapperBase, etc);
    • at least one view - each one is a view for at least one viewmodel from the core project;
    • custom UI code for controls, gestures, events, etc.

How a MugenMvvm Application Starts

Launching an application consists of several stages:

  • the native Application will be started first;
  • during startup, the application must create a Bootstrapper class that is responsible for the creation and launch of the MugenMvvm application:
    • the Bootstrapper will create the IoC container and provide an array of assemblies;
    • then Setup will call into the core project, construct an IMvvmApplication and call Initialize on it (if you do not have an IMvvmApplication implementation the Bootstrapper would create a default application);
    • during the initialization your App will typically:
      • sets the current LoadMode and creates the IModuleContext that will be used for filtering and loading of modules;
      • finds and loads all implementations of IModule interface;
      • provides the start viewmodel type.
  • the Bootstrapper will start presenting the start viewmodel using a databound view.

The MugenMvvm Core

the "core" layer consists of:

  • App class - an application object that implements the IMvvmApplication interface - typically in App.cs;
  • at least one viewmodel - each of them responsible for a piece of user interaction with your models or services;
  • your services, models and 'business' code.

App.cs

The App class should be located in the Core project and implement the IMvvmApplication interface. For convenience, this interface is already implemented in the MvvmApplication class.
App allows the start viewmodel type to be controlled by implementing or overriding GetStartViewModelType.
App allows to control start viewmodel type of the application as far as loading of IModule classes.

The key method within an App is Initialize. This method will be called on start up.

The specific jobs your App should do during its Initialize are:

  • load all modules (IModule implementations);
  • register all services.

Here is an example of App taken from Order Manager example app:

using System;
using MugenMvvmToolkit;
using OrderManager.Portable.ViewModels;

namespace OrderManager.Portable
{
    public class App : MvvmApplication
    {
        #region Methods

        public override Type GetStartViewModelType()
        {
            return typeof (MainViewModel);
        }

        #endregion
    }
}

This App within GetStartViewModelType getting the type of start viewmodel (MainViewModel).

ViewModels

In each MugenMvvm 'core' application your ViewModels provide containers for the state and the behaviour for your User Interface.

Typically they do this using:

  • C# Properties
  • the INotifyPropertyChanged and INotifyCollectionChanged interfaces to send notifications when properties change
  • special ICommand properties which can allow View events (e.g. button taps) to call actions within the ViewModel

In MugenMvvm, any viewmodel normally inherit from one of the next base viewmodel classes:

  • ViewModelBase
  • CloseableViewModel
  • ValidatableViewModel
  • EditableViewModel
  • WorkspaceViewModel
  • GridViewModel
  • MultiViewModel

A typical ViewModel might look like:

public class VideoViewModel : ViewModelBase
{
  private string _email;

  public string Email
  {
    get { return Entity.Name; }
    set
    {
       if (Equals(Entity.Name, value))
         return;
      _email = value;
      OnPropertyChanged();
    }
  }

  public ICommand OpenVideoWorkspaceCommand { get; private set; }

  protected override void OnInitialized()
  {
    base.OnInitialized();
    OpenVideoWorkspaceCommand = new RelayCommand(OpenVideoWorkspace);            
  }

  private async void OpenVideoWorkspace(object obj)
  {	
    using (var videoWorkspaceViewModel = GetViewModel<VideoWorkspaceViewModel>())
      await videoWorkspaceViewModel.ShowAsync();
  }     
}

This VideoViewModel has:

  • a single Email property raises a PropertyChanged notification when it changes;
  • a single OpenVideoWorkspaceCommand command which will call the OpenVideoWorkspace() method whenever the command is executed.

In order to get more information about each viewmodel base class see Toolkit architecture docs.

The MugenMvvm UI

An typical MugenMvvm 'ui' layer provides:

  • the native platform-specific application code - e.g Main.cs and AppDelegate.cs on Xamarin.iOS;
  • a Setup.cs class;
  • one or more Views - each one responsible for presenting one of your viewmodels;
  • custom UI code - for controls, gestures, events, etc.

Platform specific application code

Android

On Android we usually have Activity used to show splash screen. MugenMvvm provides SplashScreenActivityBase in order to get more convenient way to bind MugenMvvm and SplashScreenActivity. Below presented is an example of how Android app initialization might looks like:

using Android.App;
using MugenMvvmToolkit.Android.Infrastructure;
using MugenMvvmToolkit.Android.Views.Activities;

namespace MyAndroidApp.Views
{
  [Activity(Label = "@string/application_name", MainLauncher = true,
            Icon = "@drawable/ic_launcher", NoHistory = true)]
  public class SplashScreenActivity : SplashScreenActivityBase
  {
    protected override AndroidBootstrapperBase CreateBootstrapper()
    {
      return new Setup();
    }
  }
}

Please note that ActivityAttribute has MainLauncher property setted to true in order to ensure that this is the first activity created when Adroid app starts.

iOS

On iOS, we need to override some methods of the normal AppDelegate.cs class.
Presented below is an example how AppDelegate.cs might looks like:

using Foundation;
using UIKit;
using MugenMvvmToolkit;
using MugenMvvmToolkit.iOS;
using MugenMvvmToolkit.iOS.Infrastructure;

namespace OrderManager.Touch
{
    [Register("AppDelegate")]
    public class AppDelegate : MvvmAppDelegateBase
    {
        #region Methods

        protected override TouchBootstrapperBase CreateBootstrapper(UIWindow window)
        {
            return new Bootstrapper<App>(window, new MugenContainer());
        }

        #endregion
    }
}

UWP

Typical new UWP project contains a native App.xaml.cs. In order to adapt it to use MugenMvvm we have to inherit it from MvvmUwpApplicationBase:

According to these steps we will get some code similar presented below sample:

using Windows.ApplicationModel;
using Windows.ApplicationModel.Activation;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media.Animation;
using Windows.UI.Xaml.Navigation;

namespace MyUwpApp
{
    sealed partial class App
    {
        #region Methods

        protected override UwpBootstrapperBase CreateBootstrapper(Frame frame)
        {
            return new Bootstrapper<Portable.App>(frame, new MugenContainer(), new[]
            {
                typeof(App).GetTypeInfo().Assembly,
                typeof(MainViewModel).GetTypeInfo().Assembly
            });
        }

        #endregion
    }
}
<uwp:MvvmUwpApplicationBase
    x:Class="Binding.UWP.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:Binding.UWP"
    xmlns:uwp="using:MugenMvvmToolkit.UWP"
    xmlns:binding="using:Binding"
    RequestedTheme="Light">
</uwp:MvvmUwpApplicationBase>

Xamarin.Forms

In Xamarin.Forms App inherits MvvmXamarinApplicationBase class.
Presented below is an example of how XamForms App class might looks like:

using MugenMvvmToolkit;
using MugenMvvmToolkit.Xamarin.Forms.Infrastructure;
using Xamarin.Forms;

namespace MyXamFormsApp
{
    public class App : MvvmXamarinApplicationBase
    {
        #region Constructors

        public App(XamarinFormsBootstrapperBase.IPlatformService platformService) : base(platformService)
        {
        }

        #endregion

        #region Methods

        protected override XamarinFormsBootstrapperBase CreateBootstrapper(XamarinFormsBootstrapperBase.IPlatformService platformService, IDataContext context)
        {
            return new Bootstrapper<Portable.App>(platformService, new MugenContainer());
        }

        #endregion
    }
}

BootstrapperBase class

The BootstrapperBase class is the bootstrapper for the MugenMvvm system.
This class has the next abstract methods:

  • CreateApplication - must returns platform specific implementation of IMvvmApplication interface i.e. a new instance of your platform specific App object.
  • CreateIocContainer - must returns implementation of IIocContainer interface. That allows to users use any DI container they wish.
  • InitializeInternal - must creates an instances of IMvvmApplication, IIocContainer and invoke IMvvmApplication.Initialize method.

There are exists some default platform specific BootstrapperBase implementations (TouchBootstrapperBase (iOS), AndroidBootstrapperBase (Android)). However, you are free to customize MugenMvvm bootstrapper as you wish.

Views

Each UI Platform needs a set of Views.

Each View is normally databound to a single ViewModel for its entire lifetime.

On each platform, views in the Mvvm sense are typically implemented using data-bound versions of:

  • Windows platforms - UserControl - for WindowsStore and WindowsPhone, this is very often specialised into Page;
  • Android - an Activity or Fragment;
  • iOS - UIViewController;

By default views are associated with viewmodels using a naming convention.
mapping from ViewModel to View occurs dynamically.
The IViewMappingProvider interface is used to create mappings, by default it uses the naming convention. For ViewModel it removes following closure:
"ViewModel", "Vm"
and for View:
"ActivityView", "FragmentView", "WindowView", "PageView", "FormView", "Form", "View", "V", "Activity", "Fragment", "Page", "Window"
and if then the names are the same, it is believed that the View corresponding to ViewModel.
Mapping example:
MainViewModel, MainVm -> MainActivityView, MainFragmentView, MainWindowView etc.

If you want to explicitly specify the View to ViewModel, you can use ViewModelAttribute (in this case, the naming convention is ignored):

[ViewModel (typeof(MainViewModel))]
public partial class MainWindow : Window

You can also specify a name for the View and then use it to create/display ViewModel:

[ViewModel (typeof (ItemViewModel), "ViewName")]
public partial class ItemView: Window

// Create a ViewModel and explicitly specify the name of the View
// At the time of display ViewModel provider will search View with a name ViewName
var viewModel = GetViewModel <ItemViewModel> (parameters: NavigationConstants.ViewName.ToValue ("ViewName"));
// Create a ViewModel
var viewModel = GetViewModel <ItemViewModel> ();
// Explicitly specify that you want to use View with the name ViewName
viewModel.ShowAsync (NavigationConstants.ViewName.ToValue ("ViewName"));