This article is targeted to run from UWP 10.
Create a new Xamarin Forms project, you will see Xamarin forms portable project library
along with all the platform project templates as below:

Update the Xamarin forms nuget to latest stable version to make use of latest features. Now, we are going to write the code in Xamarin forms portable project library which
will be reused to run in all the platforms.
Create a MVVM folder structure (View, ViewModel and Model) in Xamarin forms project
and add respective files appropriately.
In MVVM, INotifyPropertyChanged interface is used to notify clients, typically a
binding clients, that a property value has changed.
Create a ModelBase class to implement INotifyPropertyChanged interface and use this
class as base class for all the view models and models to raise property changes.
public class ModelBase: INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = this.PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Create a BaseViewModel, to have all common functions like commands, navigation service
and notify event.
public abstract class BaseViewModel: ModelBase
{
protected BaseViewModel(IAppNavService navService)
{
}
public abstract Task Init();
public virtual void OnNavigatedTo()
{
// called when view appearing
}
public virtual void NavigateBack()
{
}
}
public abstract class BaseViewModel<TParameter> : BaseViewModel
{
public BaseViewModel(IAppNavService navService) : base(navService)
{
}
public override async Task Init()
{
await this.Init(default(TParameter));
}
public abstract Task Init(TParameter parameter);
}
In MVVM, navigation service has to be implemented to navigate between the views.
Create a navigation interface with below set of function declarations.
public interface IAppNavService
{
void RegisterMapping(Type viewModel, Type view);
bool CanGoBack { get; }
Task GoBack();
Task NavigateTo<TVM>()
where TVM : BaseViewModel;
Task NavigateTo<TVM, TParameter>(TParameter parameter)
where TVM : BaseViewModel;
void RemoveLastView();
void ClearBackStack();
}
This service has methods “RegisterMapping”, to be used to map ViewModel to View by Binding Context.
CanGoBack, to be used to check whether the active view can be navigated back.
NavigateTo, to be used to navigate between the views, pass parameter between the views if required.
RemoveLastView, to be used to remove the last view from navigation stack, generally used to remove
the loginview from stack once user is logged in.
ClearBackStack, to be used to clear the navigation stack.
Implementation of navigation service as follows.
public class AppNavService : IAppNavService
{
private readonly INavigation navigationRoot;
private readonly IDictionary<Type, Type> map = new Dictionary<Type, Type>();
public AppNavService(INavigation navigation)
{
this.navigationRoot = navigation;
}
public bool CanGoBack
{
get
{
return this.navigationRoot.NavigationStack != null
&& this.navigationRoot.NavigationStack.Count > 0;
}
}
public async Task NavigateTo<TVM>() where TVM : BaseViewModel
{
await this.NavigateToView(typeof(TVM));
if (this.navigationRoot.NavigationStack.Last().BindingContext is BaseViewModel)
{
await ((BaseViewModel)this.navigationRoot.NavigationStack.Last().BindingContext).Init();
}
}
public async Task NavigateTo<TVM, TParameter>(TParameter parameter) where TVM : BaseViewModel
{
await this.NavigateToView(typeof(TVM));
if (this.navigationRoot.NavigationStack
.Last().BindingContext is BaseViewModel<TParameter>)
{
await ((BaseViewModel<TParameter>)this.navigationRoot.NavigationStack.Last().BindingContext).Init(parameter);
}
}
public void RegisterMapping(Type viewModel, Type view)
{
this.map.Add(viewModel, view);
}
public void RemoveLastView()
{
if (this.navigationRoot.NavigationStack.Any())
{
var lastView = this.navigationRoot.NavigationStack[this.navigationRoot.NavigationStack.Count - 2];
this.navigationRoot.RemovePage(lastView);
}
}
public void ClearBackStack()
{
if (this.navigationRoot.NavigationStack.Count <= 1)
{
return;
}
for (var i = 0; i < this.navigationRoot.NavigationStack.Count - 1; i++)
{
this.navigationRoot.RemovePage(this.navigationRoot.NavigationStack[i]);
}
}
public async Task GoBack()
{
if (this.CanGoBack)
{
await this.navigationRoot.PopAsync(true);
}
}
private async Task NavigateToView(Type viewModelType)
{
Type viewType;
if (!this.map.TryGetValue(viewModelType, out viewType))
{
throw new ArgumentException("No view found in View Mapping for " + viewModelType.FullName + ".");
}
var constructor = viewType.GetTypeInfo()
.DeclaredConstructors
.FirstOrDefault(dc => dc.GetParameters().Count() <= 0);
var view = constructor.Invoke(null) as Page;
var vm = ((App)Application.Current).Kernel.GetService(viewModelType);
view.BindingContext = vm;
await this.navigationRoot.PushAsync(view, true);
}
}
In MVVM, Dependency Injection or IOC is required to register and resolve the dependencies.
The dependencies can be view models, Repositories or services. In Xamarin forms project, we use NInject as one of the IOC container to register
the dependencies.
Install the nugget package Portable.NInject in all the projects and create a NinjectModule
similar to ServiceLocator or Bootstrap as below
public class AppModule : NinjectModule
{
private readonly INavigation navigation;
public AppModule(INavigation nav)
{
this.navigation = nav;
}
public override void Load()
{
// service dependencies
this.Bind<INavigation>()
.ToMethod(x => this.navigation)
.InSingletonScope();
this.Bind<IAppNavService>().To<AppNavService>().InSingletonScope();
// ViewModels
this.Bind<MainViewModel>().ToSelf();
this.Bind<SecondViewModel>().ToSelf();
}
public void Map(IAppNavService navigationService)
{
// Register view mappings
navigationService.RegisterMapping(
typeof(MainViewModel),
typeof(MainView));
navigationService.RegisterMapping(
typeof(SecondViewModel),
typeof(SecondView));
}
}
This module has a Load method to register the dependencies. Also added a method Map
to associate View and ViewModels.
Now, load the platform module and set the start page in app.xaml.cs
public App(params INinjectModule[] platformModules)
{
this.InitializeComponent();
// Main page root
var mainPage = new NavigationPage(new MainView());
var module = new AppModule(mainPage.Navigation);
this.Kernel = new StandardKernel(module);
// Platform specific kernel initialization
this.Kernel.Load(platformModules);
var appNavigationService = this.Kernel.Get<IAppNavService>();
// view and view model mappings
module.Map(appNavigationService);
// Get the MainViewModel from the IoC
mainPage.BindingContext = this.Kernel.Get<MainViewModel>();
this.MainPage = mainPage;
}
As this article is targeting for UWP, add the platform Ninject module in UWP project
as below. Use the same code in android, ios project templates as well if you
want to run the same app.
public class UWPAppModule : NinjectModule
{
public override void Load()
{
}
}
Now, Open MainPage.Xaml.cs in UWP project, pass this module to xamarin forms App.
public sealed partial class MainPage
{
public MainPage()
{
this.InitializeComponent();
LoadApplication(new XamarinFormsIOC.App(new UWPAppModule()));
}
}
That’s it. We are done with MVVM architectural changes required to be implemented
in real time projects. Add below code in view model to navigate one view to another view.
private async void Navigate()
{
await this.navService.NavigateTo<SecondViewModel>();
}
If you want to use the NavigatedTo and NavigateBack events, add the virtual methods
to BaseViewModel and Create a base Content Page and call these methods as below.
public class FormsPage : ContentPage
{
public FormsPage()
{
}
protected override void OnAppearing()
{
base.OnAppearing();
NavigationPage.SetHasNavigationBar(this, false);
var vm = this.BindingContext as BaseViewModel;
if (vm != null)
{
vm.OnNavigatedTo();
}
}
/// <summary>
/// The on back button pressed.
/// </summary>
/// <returns>
/// The <see cref="bool"/>.
/// </returns>
protected override bool OnBackButtonPressed()
{
var bindingContext = this.BindingContext as BaseViewModel;
if (bindingContext != null)
{
bindingContext.NavigateBack();
}
return base.OnBackButtonPressed();
}
}
Now the view becomes as below
<form:FormsPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:form="clr-namespace:XamarinFormsIOC.Views"
x:Class="XamarinFormsIOC.Views.SecondView">
<Label Text="Second View" VerticalOptions="Center" HorizontalOptions="Center" />
</form:FormsPage>
And the View Model as below.
public class SecondViewModel : BaseViewModel<Employee>
{
public SecondViewModel(IAppNavService navService) : base(navService)
{
}
public async override Task Init(Employee param)
{
// initilization
}
public override void OnNavigatedTo()
{
base.OnNavigatedTo();
}
public override void NavigateBack()
{
base.NavigateBack();
}
}
Download the working sample from below location
http:// nullskull.com/FileUpload/-407123783_XamarinFormsIOC.zip