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 inApp.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.
- App class - an application object that implements the
-
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.
- MugenMVVM Setup class - this class is the "bootstraper" for your UI and inherits from the platform specific
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 anIMvvmApplication
implementation the Bootstrapper would create a default application); - during the initialization your App will typically:
- sets the current
LoadMode
and creates theIModuleContext
that will be used for filtering and loading of modules; - finds and loads all implementations of
IModule
interface; - provides the start viewmodel type.
- sets the current
- 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 inApp.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
andINotifyCollectionChanged
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 theOpenVideoWorkspace()
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 invokeIMvvmApplication.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 intoPage
; - Android - an
Activity
orFragment
; - 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"));
Updated about 7 years ago