MvvmLight navigation in Xamarin.Forms

MvvmLight is a very popular Mvvm framework created by Laurent Bugnion. I like to use MvvmLight but when developing mobile apps I miss the possibility to create modals, so I created an extension to the navigation service in MvvmLight, read more about it here.

We can also use MvvmLight when we developing apps with Xamarin.Forms but there are no navigation service implementation for it. Because of that I have added that to my MvvmLight Navigation Service Extension. The code and complete samples can be found on GitHub.

The first step to use it is to install the nuget package.

install-package MvvmLightNavigationServiceExtension.Forms

Next step is to configure the navigation service. This is pretty much the same as if we use MvvmLight in other project. The important part here is the Initialize method that require a Xamarin.Forms navigation object. We will get the navigation object from a NavigationPage that we create before we starting to configure MvvmLight. In this sample and the in the sample code on GitHub I will use Autofac as IoC container. All the code below should be in the constructor of the App class in your Xamarin.Forms project.

navigationPage = new NavigationPage();
 
var navigationService = new NavigationService();
navigationService.Initialize(navigationPage.Navigation);
 
navigationService.Configure("Main", typeof(MainView));
navigationService.Configure("About", typeof(AboutView));
 
var builder = new ContainerBuilder();
builder.RegisterInstance<INavigationService>(navigationService);
 
var container = builder.Build();
 
ServiceLocator.SetLocatorProvider(() => new AutofacServiceLocator(container));
 
navigationPage.PushAsync(new MainView());
 
MainPage = navigationPage;

To use it in a ViewModel we need to resolve the INavigationService interface.

var navigation = ServiceLocator.Current.GetInstance<INavigationService>();
navigation.NavigateTo("About");

We can also have a parameter with the NavigateTo method, but then the view we navigating to need to have a constructor with one parameter.

var navigation = ServiceLocator.Current.GetInstance<INavigationService>();
navigation.NavigateTo("About", myParameter);
public MySecondView(object parameter)
{
     //Do something with the parameter.
}

If we want to use OpenModal method from the MvvmLight Navigation Extension we had to add a using to it.

using MvvmLightNavigationExtension;
var navigation = ServiceLocator.Current.GetInstance<INavigationService>();
navigation.OpenModal("About");

If you have feedback, feel free to contact me.

MvvmLight Navigation Extension

When navigating in iOS we can choose to do a modal navigation. That means that we open a page that is on top of the other pages and not included in the navigation stack. When using MvvmLight we only have one method (NavigateTo) when we want to open a new page.

While I want to use MvvmLight and open “modals” I have created a MvvmLight extension for iOS (for storyboards only in this pre version) and Android, https://www.nuget.org/packages/MvvmLightNavigationServiceExtension. If you’re interested in the source, it will be at GitHub, https://github.com/dhindrik/MvvmLightNavigationExtension.

While this is a pre release, feedback is very welcome!

Using the extension from shared code
To use it in your ViewModels you need to add the namespace to the class.

using MvvmLightNavigationExtension;
var navigation = ServiceLocator.Current.GetInstance();
navigation.OpenModal("Page2");

Setup
We will configure the NavigationService in same way as when we using NavigationService from MvvmLight but we using NavigationServiceExtension() instead of NavigationService and our instance of NavigationServiceExtension should be registered to both INavigationService and INavigationServiceExtension.

iOS:

 var nav = new MvvmLightNavigationExtension.iOS.NavigationServiceExtension();
 nav.Initialize((UINavigationController)Window.RootViewController);
 nav.Configure("Page1", "MainView");
 nav.Configure("Page2", "PageView");
 
container.RegisterInstance(nav);
container.RegisterInstance(nav);

Android:

 var nav = new MvvmLightNavigationExtension.Droid.NavigationServiceExtension();
 nav.Initialize():
 nav.Configure("Page1", "MainView");
 nav.Configure("Page2", "PageView");
 
container.RegisterInstance(nav);
container.RegisterInstance(nav);

MvvmLight and Xamarin.Android

Last week I wrote a blog post about Xamarin.iOS and MvvmLight. Now it’s time for the second post about MvvmLight, this time about how to use it with Xamarin.Android.

Because I put the ViewModels in a separate project I can use the same ViewModels for both Android and iOS.

First we install the NuGet package for MvvmLight to the Android project.

Install-package MvvmLightLibs

The ViewModels that we will use is the same as in the iOS app and it will look like this.

public class MainViewModel : ViewModelBase
    {
        private string _name;
 
        public string Name
        {
            get
            {
                return _name;
            }
            set
            {
                _name = value;
                RaisePropertyChanged("Name");
            }
        }
 
        public RelayCommand Send
        {
            get
            {
                return new RelayCommand(() =>
                {
                        var nav = ServiceLocator.Current.GetInstance<INavigationService>();
                        nav.NavigateTo(Views.Hello.ToString(), Name);                    
                });
            }
        }
    }

Navigation

MvvmLight has a INavigationService interface that uses for navigation and each platform will have their own implementation. For Android we will do the configuration in MainActivity. Important is to check if navigation already has been initialized. The code will just run once.

if(!_isInitialized)
{
      var nav = new NavigationService();            
      nav.Configure(Core.Views.Main.ToString(), typeof(MainActivity));
      nav.Configure(Core.Views.Hello.ToString(), typeof(HelloActivity));
 
     _isInitialized = true;
}

In my example I using Autofac for IoC, we can also use the IoC container that is in the MvvmLight package. When we have created the NavigationService we had to register it in the IoC container as a INavigationService.

var builder = new ContainerBuilder();
builder.RegisterInstance<INavigationService>(nav);
 
builder.RegisterType<MainViewModel>();
builder.RegisterType<HelloViewModel>();
 
var container = builder.Build();
 
var serviceLocator = new AutofacServiceLocator(container);
 
ServiceLocator.SetLocatorProvider(() => serviceLocator);

To navigate we will resolve the INavigationService interface and use the NavigateTo method.

var nav = ServiceLocator.Current.GetInstance<INavigationService>();
nav.NavigateTo(Views.Hello.ToString(), "Navigation paramter");

To retrieve the parameter we are using the GetAndRemoveParameter in the NavigationService class. Note that this is an Android specific method so we have to cast the INavigationService to NavigationService.

var nav = (NavigationService)ServiceLocator.Current.GetInstance<INavigationService>();
var param = nav.GetAndRemoveParameter<string>(Intent);
 
ViewModel = ServiceLocator.Current.GetInstance<HelloViewModel>();
ViewModel.Name = param;

Databindings

When using MVVM we want to use data bindings. In Android we have to create the bindnings in code. MvvmLight will help us with that. In the class for the Activity we hade to add a using to the MvvmLight helpers.

using GalaSoft.MvvmLight.Helpers;

The activity also has to inherit from ActivityBase (GalaSoft.MvvmLight.Views.ActivityBase).

public class HelloActivity : ActivityBase
{

The MvvmLight helper namespace will contains the extension methods SetBinding and SetCommand.

The fields that vi are creating bindings to need to be declared as public in the Activity.

public EditText Text { get; private set; }
 
protected override void OnCreate(Bundle bundle)
{
     var button = FindViewById<Button>(Resource.Id.send);
     Text = FindViewById <EditText>(Resource.Id.name);
 
     this.SetBinding(() => ViewModel.Name,() => Text.Text, BindingMode.TwoWay);
     button.SetCommand("Click", ViewModel.Send);
}

The SetCommand method’s first argument will be which event that will execute the command.

I create the ViewModel in the OnCreate method using the ServiceLocator, I prefer to create it with the ServiceLocator directly instead of wrapping it in a ViewModelLocator which is a common way to do it when using MvvmLight.

The complete code for this sample is on GitHub, https://github.com/dhindrik/XamarinMvvmLightSample

Use MvvmLight in Xamarin.iOS

I think MVVM is a good design pattern to separate UI and business logic. MvvmLight is one of the most popular frameworks for MVVM. In this blog post I will show how you can use MvvmLight when we’re building a iOS app with Xamarin.

The fist step is to create a view model. I always have my view models in a PCL (Portable Class Library) so I can share the view models with other platforms, Android and Windows for example.

When I have created a new project I will install MvvmLight to it. The easiest way to do that is to install the NuGet package for MvvmLight. The package should be added to both the PCL project and the iOS project.

Install-package MvvmLightLibs

When we are working with MVVM all ViewModels need to implement the INotifyPropertyChanged interface. INotifyPropertyChanged has one event handler, PropertyChanged that we have to implement. When using MvvmLight this is done in a base class called ViewModelBase.

In my example the viewmodel

public class MainViewModel : ViewModelBase
{
        private string _name;
 
        public string Name
        {
            get
            {
                return _name;
            }
            set
            {
                _name = value;
                RaisePropertyChanged("Name");
            }
        }
 
        public RelayCommand Send
        {
            get
            {
                return new RelayCommand(() =>
                {
                    var nav = ServiceLocator.Current.GetInstance<INavigationService>();
                    nav.NavigateTo(Views.Hello.ToString(), Name);  
                });
            }
        }
}

Navigation

MvvmLight has a INavigationService interface that uses for navigation and each platform will have their own implementation. On iOS you need to create a NavigationService and configure it in the AppDelegate class.

var nav = new NavigationService();
nav.Initialize((UINavigationController)Window.RootViewController);
nav.Configure(Views.Main.ToString(), "MainView");
nav.Configure(Views.Hello.ToString(), "HelloViewController");

In my example I using Autofac for IoC, we can also use the IoC container that is in the MvvmLight package. When we have created the NavigationService we had to register it in the IoC container as a INavigationService.

var builder = new ContainerBuilder();
builder.RegisterInstance<INavigationService>(nav);
 
builder.RegisterType<MainViewModel>();
builder.RegisterType<HelloViewModel>();
 
var container = builder.Build();
 
var serviceLocator = new AutofacServiceLocator(container);
 
ServiceLocator.SetLocatorProvider(() => serviceLocator);

If you’re using storyboards you have to use the Configure(string key, string storyboardId) method. The key is just a key that we set to the view, we will use that key when we will navigate to the view. (See the code fore the ViewModel above. StoryboardId is a property that we’re setting in the storyboard designer.

Properties

Data bindings

When using MVVM we want to use data bindings. In iOS we have to create the bindnings in code. MvvmLight will help us with that. In the class for the UIViewController we hade to add a using to the MvvmLight helpers.

using GalaSoft.MvvmLight.Helpers;

The MvvmLight helper namespace will contains the extension methods SetBinding and SetCommand.

When binding to a UITextField we can set which event who will trigger an update of the our ViewModel with the method UpdateSourceTrigger. WhenSourceChange is used to set which property in the ViewModel who will be updated.

The SetCommand method’s first argument will be which event that will execute the command.

public override void ViewDidLoad()
{
            base.ViewDidLoad();
 
           //Creates a binding to a UILabel
            this.SetBinding(() => ViewModel.Name, () => MyLabel.Text);
 
           //Creates a binding to a UITextField
            this.SetBinding(() => Name.Text).
                UpdateSourceTrigger("EditingChanged").
                WhenSourceChanges(() => ViewModel.Name = MyTextField.Text);
 
            //Binding a command to the Button.
            MyButton.SetCommand("TouchUpInside", ViewModel.Send);
}

The complete code for this sample is on GitHub, https://github.com/dhindrik/XamarinMvvmLightSample