The MVVM Light NavigationService part 4: Xamarin.Android

Introduction

This series of articles documents how to use the MVVM Light NavigationService on all supported platforms.

In this article, we will see how the NavigationService works in Xamarin.Android when the user interface is defined with an AXML file.

See the bottom of this article for a working sample!

Creating the application

In Android, you can define the UI in an AXML file (an XML-based file), or in code. Each view has a separate AXML file which is loaded by the Activity (the controller) when it is created. In Xamarin, you can edit the AXML file using a visual designer, either in Visual Studio (Windows only) or in Xamarin Studio (Windows and Mac).

We will start by creating a new application with three pages. You can do the same in Xamarin Studio, but here we will do it in Visual Studio. Also, note that we will keep things concentrated on the NavigationService only, and we won’t use viewmodels, but trigger the navigation directly from the view.

  • In Visual Studio, select File, New, Project.
  • In the New Project dialog, select Visual C# / Android / Blank App.
  • Give a name to the new app and click OK.

This creates a Xamarin.Android project with a MainActivity and the corresponding AXML file in the Resources/Layout folder.

  • In order to run the application on your device of choice, you need to set the SDK level to the one corresponding to your device or emulator. In my case, I use level 19.
  • Right click on the project and select Properties from the context menu.
  • Change Compile using Android version to “API Level 19” (or the level corresponding to your device/emulator).
  • Answer OK to the dialog asking you if you want to close and reopen the project.

Now we will add two more activities with their AXML files.

  • In the Solution Explorer, right click on the newly created project and select Add, New Item.
  • In the Add New Item dialog, select Visual C# and then Activity.
  • Name the new item Page2Activity and click OK.
  • Repeat the same for Page3Activity.
  • Then right click on the Resources/Layout folder and select Add, New Item.
  • In the Add New Item dialog, select Android Layout.
  • Name the new item Page2.axml and click OK.
  • Repeat the same for Page3.axml.

At this point, your Solution Explorer should look like this:

2015-02-16_17-56-04

Creating the UI

Now we will design a simple UI for the navigation. Start by double clicking Main.axml. You should see the screen showing up in the designer.

2015-02-16_18-24-11
  • Click the button and select the Properties tab.
  • Locate the Text property and set it to “Navigate to Page 2”.
  • In the Solution Explorer, open Page2.axml. It should show an empty page.
  • Open the Toolbox (View, Toolbox) and drag a Button on the page’s surface.
  • With the button selected, set the Text property to “Navigate to Page 3 with parameter”.
  • Set the ID property to “@+id/NavigateButton”.
  • Open Page3.axml and add a new button too.
  • Set the button’s text to “Go back to Page 2” and its ID to “@+id/GoBackButton”.
  • Add a TextView below the button.
  • With the TextView selected, set the text property to “Nothing yet”.
  • Set the gravity to center, and the ID to “@+id/DisplayText”. You can also set the textSize to 24dp.

Installing MVVM Light

In order to use MVVM Light, we will pull the latest version from Nuget.

  • Right click on the project in the Solution Explorer, and select Manage NuGet Packages.
  • Select the nuget.org repository (under Online) and enter "mvvmlight" in the Search field.
  • Select the "MVVM Light libraries only" package and click on Install.
  • Follow the instructions.

Initializing and registering the NavigationService

Now we will initialize the navigation service and the IOC container.

  • In the Solution Explorer, open the MainActivity.
  • Modify the MainActivity declaration to inherit from GalaSoft.MvvmLight.Views.ActivityBase instead of Android.App.Activity. This utility class is useful for navigation scenarios.
[Activity(
    Label = "NavigationDroid",
    MainLauncher = true, 
    Icon = "@drawable/icon")]
public class MainActivity : ActivityBase
  • Change the "OnCreate" method as shown below. Because a simple Android application doesn’t have an “App” class which is the entry point, we will instead initialize the IOC container in the MainActivity which is defined as the MainLauncher. In more complex applications, we could define an “App” class which takes care of the initialization when the application starts up.
    • The first line configures the ServiceLocator, so we can use it in a standard manner throughout the application. For more details on this, see CommonServiceLocator.
    • Calling Configure adds a mapping key –> Activity type in the NavigationService. 
    • Finally, save the configured NavigationService instance in the SimpleIoc.
public const string Page2Key = "Page2";
public const string Page3Key = "Page3";

private static bool _initialized;

protected override void OnCreate(Bundle bundle)
{
    base.OnCreate(bundle);
    SetContentView(Resource.Layout.Main);
    
    if (!_initialized)
    {
        _initialized = true;
        ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
    
        var nav = new NavigationService();
        nav.Configure(Page2Key, typeof(Page2Activity));
        nav.Configure(Page3Key, typeof(Page3Activity));
    
        SimpleIoc.Default.Register<INavigationService>(() => nav);
    }
}

Navigating to another controller

Now we will trigger the navigation. As stated before, the navigation can be triggered from any location in the application, including shared code in a portable class library, etc. Here, to keep things simple, we will not add any viewmodels but just use the Activity code and event handlers. In a real life application, the INavigationService would be injected inside the viewmodel using dependency injection. For more information about dependency injection and IOC, see my MSDN article.

  • In the MainActivity, within the OnCreated method, below the code that you just added before, add the following:
var button = FindViewById<Button>(Resource.Id.MyButton);
button.Click += (s, e) =>
{
    var nav = ServiceLocator.Current.GetInstance<INavigationService>();
    nav.NavigateTo(Page2Key);
};
  • Open the Page2Activity and instead of inheriting from Activity, change it to ActivityBase too.
  • Then implement the OnCreated method as follows:
protected override void OnCreate(Bundle bundle)
{
    base.OnCreate(bundle);
    SetContentView(Resource.Layout.Page2);

    var button = FindViewById<Button>(Resource.Id.NavigateButton);
    button.Click += (s, e) =>
    {
        var nav = ServiceLocator.Current.GetInstance<INavigationService>();
        nav.NavigateTo(
            MainActivity.Page3Key,
            "Hello Xamarin " + DateTime.Now.ToString("HH:mm:ss"));
    };
}

Note that in this method, we are calling NavigateTo with a parameter. In this case we pass a string, but it could be any object.

Retrieving the passed parameter, going back

In Page3Activity, we will retrieve the parameter passed by Page2. Then we will display this value in the DisplayText. We will also implemement the GoBackButton’s event handler to programmatically go back to page 2. To do this, we will modify the base class of Page3Activity to be a GalaSoft.MvvmLight.Views.ActivityBase.

[Activity(Label = "Page3")]
public class Page3Activity : ActivityBase
{
    public NavigationService Nav
    {
        get
        {
            return (NavigationService)ServiceLocator.Current
                .GetInstance<INavigationService>();
        }
    }

    protected override void OnCreate(Bundle bundle)
    {
        base.OnCreate(bundle);
        SetContentView(Resource.Layout.Page3);
        
        var button = FindViewById<Button>(Resource.Id.GoBackButton);
        button.Click += (s, e) => Nav.GoBack();
        
        var label = FindViewById<TextView>(Resource.Id.DisplayText);
        var param = Nav.GetAndRemoveParameter<string>(Intent);
        label.Text = param;
    }
}

Retrieving the CurrentPageKey

It can be useful for the viewmodel to know which page is currently displayed. To do this, you can use the CurrentPageKey property. To illustrate this, implement the following code:

  • Open Page2Activity.
  • Implement the following method:
protected override void OnResume()
{
    base.OnResume();
    var nav = ServiceLocator.Current.GetInstance<INavigationService>();
    Console.WriteLine("Current page key: " + nav.CurrentPageKey);
}
  • Run the application in Debug mode (F5).
  • Navigate to Page 2 and observe the Debug console. You should see "Current page key: Page2".
  • Then navigate to Page 3. Using either the device’s Back button, or the button labeled "Go back to page 2", navigate back.
  • Observe again the Debug console. Using the built-in device’s Back button, or our own back button should not make any difference.

Conclusion

This article demonstrated how to create a new Android application with 3 pages, install MVVM Light and implement navigation between the pages, with and without a parameter. We also showed how to retrieve the parameter, and how to navigate back programmatically. Finally, we showed how to retrieve the key corresponding to the current page.

Resources

The code shown in this article is available in a sample.