DotNetCurry Logo

Using MVVM in your Xamarin.Forms app

Posted by: Gerald Versluis , on 8/9/2017, in Category Xamarin
Views: 3724
Abstract: If you have looked into Xamarin.Forms, or even built an app with it, you might have noticed that Forms has everything to implement the MVVM framework. Xamarin.Forms is already equipped with data-binding, commands and dependency injection which are some MVVM ingredients we will look at in this article.

What is MVVM?

Let me briefly explain what MVVM is, in case you don’t know it yet.

MVVM stands for Model-View-ViewModel. It is derived from the MVC pattern which you probably already know about. It is an architectural pattern which enables you to separate business logic from UI code. The pattern consists of three ingredients: Model, View and ViewModel.

The ViewModel acts as a value converter between the Model and the View. The image below shows a schematic representation.

mvvm-schema

The ViewModel is responsible for converting values in a way, for the View to present them to the user. To help you update the UI from the ViewModel, data binding is used.

Are you keeping up with new developer technologies? Advance your IT career with our Free Developer magazines covering C#, Patterns, Xamarin, .NET Core, MVC, Azure, Angular, React, and more. Subscribe to our magazines for FREE and download all previous, current and upcoming editions.

MVVM with Xamarin.Forms

Now, let us zoom in on how MVVM can be used in Xamarin.Forms apps.

If you have built a Forms app before, you will know that one of the choices you have to make early on is to use either XAML (Extensible Application Markup Language) OR code to assemble your UI.

Both have the same functionality and can do the exact same thing, it just comes down to a matter of taste.

I like to use XAML as I think it is clearer.

This is why for the rest of this article, I will use XAML. However, this choice does not mean you can only use the option you have chosen. If you decide later on to switch to code, you can and vice versa too.

If you would like, you could even mix both, although I would not recommend it.

XAML is created by Microsoft and is used extensively in Windows Presentation Foundation (WPF) applications. Although the concept is identical, the naming between these two platforms is different.

This probably is due to two main reasons: first, the naming of Xamarin XAML is adapted to be better suited for mobile concepts, and second; it prevents people from taking existing layouts in WPF and paste them into a mobile app, causing the app to be a user experience disaster.

But Xamarin.Forms has more in store for you when you want to work with MVVM. It also has data binding and commanding. We will learn about this later on.

One last thing on naming; throughout this article, I will refer to a ViewModel as a PageModel. There is no difference, it is just that a View in Xamarin (or even mobile) is refered to as a Page most of the time. To make it more clear – and simply because I have become more accustomed to it – I always use Page and PageModel.

Creating a Xamarin Sample App

The best way to learn about something is to get to work with it, so let’s create a sample app which shows us how to implement MVVM.

In this example, I will be working with Visual Studio for Mac, but everything will work just fine on Windows with Visual Studio as well, and for building Universal Windows apps (UWP).

Let’s first create a new Xamarin.Forms app. Go to File > New Solution and choose the Blank Forms App. Make sure you don’t choose the Forms App, which is a great template as well as it gives you an ASP.NET Core backend automatically, but that is not what we need right now.

In the next screen, name your app and make sure to choose a Portable Class Library for ‘Shared Code’ (I will refer to this as PCL from now on) and check Use XAML for user interface files. The last option, use XAML, is just to setup a first page for you. If you forget to check it, you can still use XAML in your project, just like you can still use code when you do use XAML.

The last screen presents you with some options to configure a repository and add a test project. We will not focus on this right now, so you can leave these options as-is.

new-xamarin-app- screen

After Visual Studio has finished processing, you should be presented with your brand-new app. I have named mine DncMvvm. Because we choose to use XAML, there is a page already in our PCL which is named after our project, so in my case DncMvvmPage.xaml.

When we open this up, there is a very simple ContentPage in it with a centered Label. We can see how it looks like in the Xamarin.Forms XAML previewer. This is a very powerful tool when designing layouts, be sure to check it out.

In this page, we will insert our first bit of MVVM and data binding.

First, let’s create a new class which we will be named DncMvvmPageModel. While naming is not important, for overview, it can be helpful to stick to a pattern of NamePage and the accompanying NamePageModel. This way you can easily see what PageModel corresponds to which Page. This will have another advantage when we are implementing a MVVM framework. This is something I will show you later in this article.

The implementation of the DncMvvmPageModel is simple; it holds one public property of type string. That is it, for now.

public class DncMvvmPageModel
{
    public string LabelText { get; set; }
}

To implement this, now go to the code-behind of our page, create a new instance of the PageModel and use it as such.

public DncMvvmPage()
{
    InitializeComponent();

    var pageModel = new DncMvvmPageModel();
    pageModel.LabelText = "Hello from the PageModel!";

    BindingContext = pageModel;
}

As you can see, a page has a property BindingContext. By assigning any type of object to this property, it will function as the PageModel for that page. You can then bind to any public property that is in the PageModel (DncMvvmPageModel in this case).

In the above code, I created an instance of the PageModel, assigned a text to the LabelText property and set the PageModel as the BindingContext for our page.

Note: This is not a best practice. The code-behind should be clear of any code as much as possible. With this sample, I just want to show you that you can set the values in your PageModel from anywhere.

There is now just one last thing to do, set the Label in the XAML of our page to use the property of our PageModel.

We replace the static text that was defined earlier like this:

<Label Text="{Binding LabelText}" VerticalOptions="Center" HorizontalOptions="Center" />

When the app is run now, you will see that the text comes out of our PageModel. This is also reflected in the XAML previewer as you can see in the figure below.

first-binding

I have divided the source code into release on my GitHub repository, you can find this first step here: https://github.com/jfversluis/DncMvvm/releases/tag/step-1.

Commands

Showing data from our PageModel is one thing, but as you can imagine, we would also like the ability to invoke some code.

Traditionally, we would do this by the means of events. However, using events requires a tight coupling between the Page and the code-behind, which is not what we want.

Therefore, Commands were invented.

Commands are basically another type we can bind to in our PageModel, but can execute code for you.

Let us have a look at how this works.

First, go to the PageModel, and add a new property of the Command type. In the code below, you see the updated PageModel.

public class DncMvvmPageModel
{
    public string LabelText { get; set; }

    public Command KnockCommand { get; }

    public DncMvvmPageModel()
    {
        KnockCommand = new Command(() => {
            LabelText = "Who's there?";
        });
    }
}

There is now a new property which I called KnockCommand. In the constructor of my PageModel, I assign it with a handler.

In the Command, I set the LabelText to a different value and expect it to be updated. To hook up our new property, go back to the XAML page and define a button which binds to our KnockCommand property.

I have juggled around with the layout a little bit to make it look better as well.

<?xml version="1.0" encoding="utf-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
    xmlns:local="clr-namespace:DncMvvm" x:Class="DncMvvm.DncMvvmPage">
    
    <StackLayout VerticalOptions="Center" HorizontalOptions="Center">
        <Label Text="{Binding LabelText}" />
        <Button Text="Knock, knock..." Command="{Binding KnockCommand}" />
    </StackLayout>
</ContentPage>

When running this code now, we see the new button and when we press it, well nothing happens!

Although if we put a breakpoint in the code of the Command, we would see that the code is triggered. To update values in the View (or Page) from the PageModel, there is something else we need to implement.

The code for implementing the Command is the second release I have created in the repository.

INotifyPropertyChanged

To update values in the UI from a PageModel, there is something we need to implement. This is the INotifyPropertyChanged interface.

With the implementation of this interface, you can notify the UI (in our case defined by XAML) that a value has changed, and needs to be retrieved from the PageModel again. Implementation is very simple, but requires some refactoring.

Shown here is the code after refactoring the interface.

public class DncMvvmPageModel : INotifyPropertyChanged
{
    private string _labelText;
    public string LabelText
    {
        get
        {
            return _labelText;
        }

        set
        {
            _labelText = value;
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(LabelText)));
        }
    }

    public Command KnockCommand { get; }

    public DncMvvmPageModel()
    {
        KnockCommand = new Command(() =>
        {
            LabelText = "Who's there?";
        });
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

As you can see, I have declared the interface after the class name. This interface forces me to implement a new public event of the type PropertyChangedEventHandler. Our binder will check to see if this interface is implemented and hook up this event automatically.

To raise this event, I needed to refactor the LabelText property to a property with a backing field. This way, I can invoke the event in the setter of this property. Now, when we run this code again, the text in our label will change!

You can imagine that as your project grows, the number of properties will grow and there will be a lot of repetitive code which just raises a flag whenever a property value is changed.

There are a number of ways to overcome this.

One is to introduce a generic base class which handles a lot of duplicate code for you. Another good option, which I tend to use almost always, is to look at the Fody.PropertyChanged (https://github.com/Fody/PropertyChanged) NuGet package. This injects the INotifyPropertyChanged code at compile-time for you. I will not handle the details in this article, but be sure to check it out.

This example only implements the INotifyPropertyChanged manually. The code for this can be found in the third release on the sample app repository.

A Bit Deeper into Data Binding

To dig a little bit deeper into data binding, we will look at how we can bind the property of one control, to the property of another.

To demonstrate how this works, we will add a Slider control to our UI and let the value of that control adjust the Rotation of our Label control. The end result is shown in the image below.

slider-example

Because we will now impact one control from another, we just need to adjust the UI code, and thus our XAML. You will see how to do it in the following code. For brevity, I have only included the StackLayout containing the controls, instead of the whole page.

<StackLayout VerticalOptions="Center" HorizontalOptions="Center">
    <Label Text="{Binding LabelText}" Rotation="{Binding Source={x:Reference AngleSlider}, Path=Value}" />
    <Button Text="Knock, knock..." Command="{Binding KnockCommand}" />
    <Slider x:Name="AngleSlider" Maximum="180" Minimum="0" />
</StackLayout>

At the bottom, I have added a slider and I gave it a name. The minimum and maximum value are set to 0 and 180 which are degrees that the Label can be rotated at.

In the Label, I have declared the Rotation attribute. Instead of the binding syntax we have seen until now, there is something different here. I will dissect it for you.

A binding declaration like {Binding PropertyName} is a shorthand for writing {Binding Path=PropertyName}. The Path parameter specifies the property of the BindingContext to look for a value.

But there are more parameters you can use.

One of them is Source. With Source, you can specify a data source. With this parameter, you can specify a different source than the BindingContext which is specified for the whole page. In this case, we set the source to another control. This is why we needed to give the Slider control a name, so we can assign it as a source.

With this in place, we can run our app and when the slider is changing value, the label will rotate accordingly.

You can imagine how powerful this is!

You can not only bind to PageModel values, but also to values of other controls or to values on the page.

This all makes for a very flexible and extensible technique creating no coupling between your Page and any business logic. Remember; the PageModel is responsible for pushing data back and forth.

The code for this phase of the app can be found in the fourth release on GitHub.

Value Converters

One last thing I want to show you is Value Converters. In the UI, a lot of properties will just show strings, which is easy. But later on, you might want to give a control a certain color or show an image depending on a certain value, etc.

I will explain this with a real-life example.

I was building an app which had to do with gaming. The app showed games with their respective platforms (PS4/Xbox). Each platform had its own color associated to it.

There are multiple ways to solve this – as always – but I chose to do it with a value converter. With a converter, you can transform a data bound property from one type to another. In this case, I took in a string, which specified the platform like PS4 or Xbox and transformed it to a color.

Let me show you this in our sample app.

I have updated my XAML page and bound my Label’s TextColor attribute to the LabelText property of my PageModel. I have done so because I want the color of the text to change based on this string value.

<Label Text="{Binding LabelText}"    TextColor="{Binding LabelText}" Rotation="{Binding Source={x:Reference AngleSlider}, Path=Value}" />

Of course, we can’t assign a string value to an attribute that expects a Color. This is where the ValueConverter comes in.

To create a converter, we need to create a new class which implements the IValueConverter interface.

public class WhosThereToColorConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var stringValue = value as string;

        if (string.IsNullOrWhiteSpace(stringValue))
            return Color.Black;

        if (stringValue.ToLowerInvariant().Contains("who"))
            return Color.Red;

        return Color.Black;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

By implementing this interface, you need to define a Convert and ConvertBack method. These methods are responsible for supplying a new value in the right type. In this case, I get the string value, which we need to cast because a conversion can be from any type, and based on what the string contains, I determine a Color.

In the above code, I check to see if the text contains ‘who’ and then change the color to red.

In many cases, ConvertBack need not be implemented. When you only need to display a value in a specific way from your PageModel to your Page, you only have to implement Convert.

When you create a TwoWay binding (the value is updated in the PageModel when you edit it in the Page), you will need to also implement the ConvertBack method to transform the value from the one shown in your UI, to a value that the PageModel understands.

So, it is effectively the inverse of the Convert method.

The last thing we need to do is to tell the binding to use the converter.

Update the XAML for the Label to this:

<Label Text="{Binding LabelText}"    TextColor="{Binding LabelText, Converter={StaticResource WhosThereToColorConverter}}" Rotation="{Binding Source={x:Reference AngleSlider}, Path=Value}" />

Notice how I added a converter parameter to the binding. This converter points to a static resource. There are multiple ways to define a static resource, but the simplest way is to define it in the same page.

You can do so like this:

<ContentPage.Resources>
    <ResourceDictionary>
        <local:WhosThereToColorConverter x:Key="WhosThereToColorConverter" />
    </ResourceDictionary>
</ContentPage.Resources>

The Key has to correspond with the StaticResource parameter on the binding. When we run this code and press the button, the text will change to ‘Who’s there?’ and because that contains ‘who’, the color will also change accordingly.

The code for this can be found in the fifth release on the repository.

Using a MVVM Framework

A lot of people have already gone ahead and implemented the MVVM pattern. As such, there are also a lot of frameworks out there that can help you with this. Not only will they make your life easier, they also provide you with even more power and decoupling of your code.

There are multiple good frameworks out there, even from before the time that Xamarin.Forms was invented. They include, but are not limited to:

  • MVVM Light
  • Prism
  • Caliburn.Micro
  • and the very popular MvvmCross.

All these frameworks do a great job, and basically provide you with the same thing, they just have their own accent on certain aspects.

The framework I like to use is FreshMvvm (github.com/rid00z/FreshMvvm) by Michael Ridland.

This framework is very easy to use and very lightweight. Because Xamarin.Forms already has so many aspects of MVVM already implemented, a few optimizations are all we need.

That is exactly what was in mind when FreshMvvm was designed.

This framework was built specifically for Xamarin.Forms and therefore the naming is done appropriately. Everything is named with Pages and PageModels, while the naming convention with View will also work.

FreshMvvm as a MVVM framework

In this last part of my article, I will show you what is involved in implementing FreshMvvm as a MVVM framework and how it helps you optimize your code even further.

Installing is very easy, just install the NuGet package in your PCL project and that is it.

Remember how I told you that it would be convenient to keep the naming convention consistent?

FreshMvvm works by this naming convention. Automatically a PageModel which could be named PersonDetailsPageModel will look for a page called PersonDetailsPage.

Also, notice how I say that the PageModel will look for a page, FreshMvvm supports PageModel-to-PageModel navigation. This means you state to which PageModel you want to navigate to, instead of referencing an actual page. This helps you to further separate your UI from other code, because now, when you want to replace a Page, just create a new one, give it the right name according to the naming convention and your new Page will be shown without touching any code at all.

While this works out of the box, you can configure this differently if you want.

For all of this to work, your PageModels now need to inherit from the FreshBasePageModel. Go into the DncMvvmPageModel and let it inherit from this base class. Now go into the App.xaml.cs file and replace the assignment of the MainPage property.

MainPage = FreshPageModelResolver.ResolvePageModel<DncMvvmPageModel>();

This way you can resolve the page that is associated to this PageModel and it is shown as the main page. When running this, it doesn’t go right because we are still setting the BindingContext from the Page’s code-behind, remove this code to make it work as it should. If done right, you do not need any code in your pages anymore, at all. Just remember that now you need resolve your pages by the PageModel to make this automatic binding work.

FreshMvvm has the most basic page types already built-in: TabbedPage, MasterDetailPage and just a ContentPage are among them. They all work with this automatic binding and you can specify PageModels which will automatically be resolved. For instance, if you want to have a page with multiple tabs, you would specify it like this:

var tabbedPage = new FreshTabbedNavigationContainer();
tabbedPage.AddTab<DncMvvmPageModel>("Home", "icon.png");
tabbedPage.AddTab<AnotherPageModel>("Another", "anothericon.png");

MainPage = tabbedPage;

To navigate from one page to another, you can use the methods that are exposed through the FreshBasePageModel. In the CoreMethods there are a lot of handy functions you can leverage among them, for navigation purposes.

You can navigate to another PageModel by executing:

CoreMethods.PushPageModel<AnotherPageModel>();

There are some overloads as well which let you supply any object with which you can send values back and forth.

For instance, imagine you are building an app which manages contacts. You can select a contact from the list which brings you to a detail page. You could supply the object with the contacts details to the PushPageModel method and fetch it in the ContactDetailPageModel.

You would do so by overriding the Init method.

This method will be invoked when a PageModel is navigated to. You can check there if an object is supplied and handle it in your target PageModel. There is also the ReverseInit which does the opposite, you can retrieve a value when a PageModel is popped.

I have added some sample code for this in the repository in the sixth step for you to examine. If you would like to know more, please do not hesitate to contact me.

Final Thoughts

In this article, I have shown you what MVVM is, some MVVM concepts and what you can gain from it. We have seen that Xamarin.Forms is already very well prepared for the usage of MVVM. With the concepts of data binding, INotifyPropertyChanged and value converters, there is very little needed, to create clean and separated code.

To take it a step further and optimize your development process, you can look at a framework, which helps you to implement MVVM in your app and takes some tedious tasks out of your hands.

I hope you will take the learning from this article and implement this in your apps. If you have any questions, please reach out to me on Twitter (@jfversluis).

All code that has been used can be found on my GitHub page https://github.com/jfversluis/DncMvvm. If you look under Releases, you can follow along step-by-step.

This article was technically reviewed by Yacoub Massad.

Was this article worth reading? Share it with fellow developers too. Thanks!
Share on LinkedIn
Share on Google+
Further Reading - Articles You May Like!
Author
Gerald Versluis (@jfversluis) is a full-stack software developer and Microsoft MVP (Xamarin) from Holland. After years of experience working with Xamarin and .NET technologies, he has been involved ina number of different projects and has been building several apps. Not only does he like to code, but he is also passionate about spreading his knowledge - as well as gaining some in the bargain. Gerald involves himself in speaking, providing training sessions and writing blogs (https://blog.verslu.is) or articles in his free time. Twitter: @jfversluis Email: gerald[at]verslu[dott]is . Website: https://gerald.verslu.is


Page copy protected against web site content infringement 	by Copyscape




Feedback - Leave us some adulation, criticism and everything in between!