---
author: "Jim Bennett"
categories: ["xamarin", "xamarin.android", "mvvmlight", "binding", "Technology", "UI", "tutorial"]
date: 2016-02-18T08:59:14Z
description: ""
draft: false
images:
- /blogs/building-a-xamarin-android-app-part-5/banner.png
featured_image: banner.png
slug: "building-a-xamarin-android-app-part-5"
tags: ["xamarin", "xamarin.android", "mvvmlight", "binding", "Technology", "UI", "tutorial"]
title: "Building a Xamarin Android app - part 5"
images:
- /blogs/building-a-xamarin-android-app-part-5/banner.png
featured_image: banner.png
---
This is the fifth part in the my series about building an Android app using Xamarin.Android. I highly recommend reading these first.
The previous parts are:
* [Creating the basic app](/blogs/building-an-android-app-part-1/)
* [Defining our data](/blogs/building-an-android-app-part-2/)
* [Building view models](/blogs/building-a-xamarin-android-app-part-3/)
* [Binding the view models to the UI](/blogs/building-a-xamarin-android-app-part-4/)
#### Adding the Add button
Currently we have a nice recycler view showing our dummy counters in card views. So the next step is to allow new counters to be added. The current way to add new items is using a floating action button - a button at the bottom of the screen that when pressed will add the new counter.

First thing to do is add it to the layout in `counters_fragment.axml`. At the moment this contains a `LinearLayout` but we'll need to change that to a `FrameLayout` so that the add button is correctly placed on top. We're not using a normal button here, but a `FloatingActionButton`, a button designed to float above other controls in the view. This means we can add a load of counters and scroll the recycler view up and down without the add button moving from it's floating location in the bottom right.
```
```
The icon being used here, `ic_add_white_24dp`, also comes from Googles material icons at https://design.google.com/icons/. Its a 24dp icon, the recommended size for floating action buttons. We don't need to set the colour of the action button, this automatically comes from the colours we added from Material Palette in [part 1](/blogs/building-an-android-app-part-1/).
#### Adding navigation
Now we have the add button, we need to think about what it needs to do. We need this button to navigate to another activity where the user can enter details about the new counter and save it. MVVMLight has a nice navigation system but we are limited in how we can use it because we are using AppCompat. Luckily I've already created a workaround which is documented [on another blog post here](/blogs/mvvmlight-navigation-and-appcompatactivity/). To add this working navigation we just need to add [the MVVMLight.AppCompat nuget package](https://www.nuget.org/packages/JimBobBennett.MvvmLight.AppCompat/), and set it up. We start with the set up by changing our `BaseActivity` to derive from `AppCompatActivityBase`.
```
public abstract class BaseActivity : AppCompatActivityBase
```
Then we need to register the navigation and dialog services with the IoC container. The concrete implementations of the services are platform specific, so we can't simply register them in the view model locator. Instead we have to expose methods to allow the registration to happen externally so that we can call it from our Android project. The following methods to register need to be added to the `ViewModelLoator`:
```
public static void RegisterNavigationService(INavigationService navigationService)
{
SimpleIoc.Default.Register(() => navigationService);
}
public static void RegisterDialogService(IDialogService dialogService)
{
SimpleIoc.Default.Register(() => dialogService);
}
```
These are then called from our `MainActivity` in a new constructor:
```
public MainActivity()
{
var navigationService = new AppCompatNavigationService();
ViewModelLocator.RegisterNavigationService(navigationService);
ViewModelLocator.RegisterDialogService(new AppCompatDialogService());
}
```
Whilst we're editing the `MainActivity` it makes sense to delete the dummy counter code as well - seeing as we are adding the ability to add new counters we don't need to pre-populate the app with fake counters. Just delete the `AddDummyData` method and the call to it.
#### Creating the new counter
To create the new counter we need to define a new activity to allow the user to enter details about the counter. This activity needs a layout, a view model and to be wired into the navigation so that we can navigate to it from our new add button.
###### Layout
Lets start with the layout. This needs to have text boxes so the user can enter the name and description for the counter, along with a button to create the new counter. We're not going to bother with a cancel option - the UI will require the create button to be clicked to create the counter with back acting as a cancel, either the back button on the tool bar or the hardware back button.
```
```
This is a standard app bar layout showing the toolbar, same as the main layout, with text boxes for the name and description, and a 'Create Counter' button. The cool thing we're doing here is the edit boxes. We're not just using a boring label with a text box below, instead we're using a `TextInputLayout`. This wraps the `EditText` so you see a hint inside the text box, then when you touch inside to enter the text the hint moves to above the box.

###### View model
Before we create an activity to show this layout, lets create the view model. We start by creating the `NewCounterViewModel` in our `ViewModel` folder. The first part of this is to create the properties to hold the name and description fields.
```
public class NewCounterViewModel : ViewModelBase
{
private string _name;
public string Name
{
get { return _name; }
set { Set(() => Name, ref _name, value); }
}
private string _description;
public string Description
{
get { return _description; }
set { Set(() => Description, ref _description, value); }
}
}
```
This view model is derived from `ViewModelBase`, and the property setters use the base class `Set` method to not only set the value but to raise the relevant property change event.
Now we have the data part sorted, it's time to add some commands.
```
public class NewCounterViewModel : ViewModelBase
{
private readonly IDatabaseHelper _databaseHelper;
private readonly IDialogService _dialogService;
private readonly INavigationService _navigationService;
public NewCounterViewModel(IDatabaseHelper databaseHelper, IDialogService dialogService, INavigationService navigationService)
{
_databaseHelper = databaseHelper;
_dialogService = dialogService;
_navigationService = navigationService;
}
private RelayCommand _goBackCommand;
public RelayCommand GoBackCommand => _goBackCommand ?? (_goBackCommand = new RelayCommand(() => _navigationService.GoBack()));
private RelayCommand _addCounterCommand;
public RelayCommand AddCounterCommand => _addCounterCommand ?? (_addCounterCommand = new RelayCommand(async () => await AddCounter()));
private async Task AddCounter()
{
if (string.IsNullOrEmpty(Name))
{
await _dialogService.ShowError("The name must be set", "No name", "OK", null);
return;
}
if (string.IsNullOrEmpty(Description))
{
await _dialogService.ShowError("The description must be set", "No description", "OK", null);
return;
}
await _databaseHelper.AddOrUpdateCounterAsync(new Counter {Name = Name, Description = Description});
_navigationService.GoBack();
}
}
```
This adds two commands.
The first is the `GoBackCommand`, which will be wired up to the toolbars back button. This uses the navigation service that is injected into the constructor to navigate back - under the hood this pops the current activity off the stack and returns to the previous one, the same as the hardware back button.
The second command, `AddCounterCommand` will create and add a new command. It starts with some simple validation to ensure the values are set, and if not raises an alert using the MVVMLight dialog service injected into the constructor. If this validation is passed the new counter is created, added to the database using the database helper injected into the constructor, and the activity is popped off the stack using the navigation service.
Like all good coders we should be testing our view model, so lets add `NewCounterViewModelTests` to the test project.
```
[TestFixture]
public class NewCounterViewModelTests
{
private Mock _mockDatabaseHelper;
private Mock _mockDialogService;
private Mock _mockNavigationService;
[SetUp]
public void SetUp()
{
_mockDatabaseHelper = new Mock();
_mockDialogService = new Mock();
_mockNavigationService = new Mock();
}
[Test]
public void SettingTheNameRaisesAPropertyChangedEvent()
{
var vm = new NewCounterViewModel(_mockDatabaseHelper.Object, _mockDialogService.Object, _mockNavigationService.Object);
vm.MonitorEvents();
vm.Name = "Foo";
vm.ShouldRaisePropertyChangeFor(v => v.Name);
}
[Test]
public void SettingTheDescriptionRaisesAPropertyChangedEvent()
{
var vm = new NewCounterViewModel(_mockDatabaseHelper.Object, _mockDialogService.Object, _mockNavigationService.Object);
vm.MonitorEvents();
vm.Description = "Foo";
vm.ShouldRaisePropertyChangeFor(v => v.Description);
}
[Test]
public void GoBackCommandNavigatesBackwards()
{
var vm = new NewCounterViewModel(_mockDatabaseHelper.Object, _mockDialogService.Object, _mockNavigationService.Object);
vm.GoBackCommand.Execute(null);
_mockNavigationService.Verify(n => n.GoBack(), Times.Once);
}
[Test]
public void AddCommandRaisesAnErrorIfTheNameIsNotSet()
{
var vm = new NewCounterViewModel(_mockDatabaseHelper.Object, _mockDialogService.Object, _mockNavigationService.Object);
vm.Description = "Bar";
vm.AddCounterCommand.Execute(null);
_mockDialogService.Verify(d => d.ShowError(It.IsAny(), It.IsAny(), It.IsAny(), null), Times.Once);
_mockDatabaseHelper.Verify(d => d.AddOrUpdateCounterAsync(It.IsAny()), Times.Never);
}
[Test]
public void AddCommandRaisesAnErrorIfTheDescriptionIsNotSet()
{
var vm = new NewCounterViewModel(_mockDatabaseHelper.Object, _mockDialogService.Object, _mockNavigationService.Object);
vm.Name = "Foo";
vm.AddCounterCommand.Execute(null);
_mockDialogService.Verify(d => d.ShowError(It.IsAny(), It.IsAny(), It.IsAny(), null), Times.Once);
_mockDatabaseHelper.Verify(d => d.AddOrUpdateCounterAsync(It.IsAny()), Times.Never);
}
[Test]
public void AddComandAddsTheCounterAndNavigatesBack()
{
var vm = new NewCounterViewModel(_mockDatabaseHelper.Object, _mockDialogService.Object, _mockNavigationService.Object);
vm.Name = "Foo";
vm.Description = "Bar";
vm.AddCounterCommand.Execute(null);
_mockDialogService.Verify(d => d.ShowError(It.IsAny(), It.IsAny(), It.IsAny(), null), Times.Never);
_mockDatabaseHelper.Verify(d => d.AddOrUpdateCounterAsync(It.IsAny()), Times.Once);
_mockNavigationService.Verify(n => n.GoBack(), Times.Once);
}
}
```
Because we're using dependency injection we can mock all the interfaces that are injected into the view model. This means we can test the behaviour of the commands ensuring the `GoBackCommand` calls the relevant `GoBack` method on the navigation service, that the navigation doesn't happen if we add a counter with data missing and that if all the information is there the counter gets added to the database. We can also check that setting the properties raises the relevant property change events. We can get pretty awesome coverage here to ensure out view model works.
The last thing to do with the view model is to add it to our locator. We need this so that the IoC container can resolve the constructor injection.
```
static ViewModelLocator()
{
...
SimpleIoc.Default.Register();
}
public const string NewCounterPageKey = "NewCounterPage";
public static NewCounterViewModel NewCounter => ServiceLocator.Current.GetInstance();
```
Here we register it with the IoC container in the constructor. Unfortunately SimpleIoC only supports singletons, so we have to always deal with a single instance - something we will have to consider later on.
Once registered we can expose a static property to return the instance, and a constant that defines a key for it. This key will be registered with the navigation service once we have defined the activity.
###### Activity
We have our layout and we have our view model, so now we can create the Activity that brings it all together.
Lets start with the basics:
```
[Activity(Label = "New Counter")]
public class NewCounterActivity : BaseActivity
{
protected override int LayoutResource => Resource.Layout.new_counter;
public override bool OnOptionsItemSelected(IMenuItem item)
{
if (item.ItemId == Android.Resource.Id.Home)
{
ViewModel.GoBackCommand.Execute(null);
return true;
}
return base.OnOptionsItemSelected(item);
}
}
```
Here we're creating the activity, derived from our `BaseActivity`. We override the `LayoutResource` to point to our new layout. We also override 'OnOptionsItemSelected' to detect if the `Home` button is pressed, executing the command on our view model to navigate backwards.
Next we need to wire up the `NewCounterViewModel`. We do this in the `OnCreate` method and store it in a public property (more on this later). As mentioned earlier the IoC container only stores singletons, so we need to clear the data before we can use it to stop the view showing the name and description of the previous counter that was added.
```
public NewCounterViewModel ViewModel { get; private set; }
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
ViewModel = ViewModelLocator.NewCounter;
ViewModel.Name = string.Empty;
ViewModel.Description = string.Empty;
}
```
Then we need to add public properties for the controls on our view.
```
private EditText _name;
public EditText Name => _name ?? (_name = FindViewById(Resource.Id.new_counter_name));
private EditText _description;
public EditText Description => _description ?? (_description = FindViewById(Resource.Id.new_counter_description));
private Button _createCounter;
public Button CreateCounter => _createCounter ?? (_createCounter = FindViewById