Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Mobile / Xamarin

Async Xamarin Forms MVVM Model

2.84/5 (10 votes)
29 Jun 2016CPOL1 min read 24.8K  
Async MVVM model template for Xamarin Forms

Image 1

Introduction

This article is about async MVVM model for Xamarin Forms.

Background

While playing with Xamarin Forms, the problem I've had is async operations on first page load. We cannot use async in constructor properly, so what I need is an async call after page load. A method come to my mind and it's working without problem, and I wanted to share it. I hope you like it.

I'll write everything from scratch. These are the current versions I've used:

  • Visual Studio 2015 Community Edition
  • Xamarin for Visual Studio (4.1.1)

Using the Code

Let's create a project and add our base model and use it. It'll take just three steps.

You can view the source code in GitHub.

1. Create a New Xamarin Forms Project (Xaml App)

Image 2

And we're ready.

Image 3

2. Create Base Model

Image 4

C#
using System.ComponentModel;
using System.Runtime.CompilerServices;

namespace AsyncTest.Models
{
    internal abstract class BaseModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

For async operations, this base model has to know which page it is bind to. So let's add it:

C#
protected Page CurrentPage { get; private set; }

Now, we need an initializer:

C#
public void Initialize(Page page)
{
    CurrentPage = page;

    CurrentPage.Appearing += CurrentPageOnAppearing;
    CurrentPage.Disappearing += CurrentPageOnDisappearing;
}

The complete code is as follows:

C#
using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using Xamarin.Forms;

namespace AsyncTest.Models
{
    internal abstract class BaseModel : INotifyPropertyChanged
    {
        protected Page CurrentPage { get; private set; }

        public event PropertyChangedEventHandler PropertyChanged;

        public void Initialize(Page page)
        {
            CurrentPage = page;

            CurrentPage.Appearing += CurrentPageOnAppearing;
            CurrentPage.Disappearing += CurrentPageOnDisappearing;
        }

        protected virtual void CurrentPageOnAppearing(object sender, EventArgs eventArgs) {}

        protected virtual void CurrentPageOnDisappearing(object sender, EventArgs eventArgs) {}

        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

As you see, base model takes page as property and creates virtual methods for "Appearing" and "Disappearing" events. If you need other events, just add them as virtual methods.

3. Create Page and Use It

We already have "MainPage.xaml", so let's use it.

First, we need a model for page.

C#
namespace AsyncTest.Models
{
    internal class MainModel : BaseModel {}
}

I'll use http://jsonplaceholder.typicode.com/ for testing.

C#
using System;
using System.Net.Http;

namespace AsyncTest.Models
{
    internal class MainModel : BaseModel
    {
        private string _responseText;

        public string ResponseText
        {
            get { return _responseText; }
            set
            {
                _responseText = value;
                OnPropertyChanged();
            }
        }

        protected override async void CurrentPageOnAppearing(object sender, EventArgs eventArgs)
        {
            ResponseText = "Loading, please wait...";
            
            try
            {
                // Wait for testing...
                await Task.Delay(TimeSpan.FromSeconds(3));
                
                using (var client = new HttpClient())
                {
                    var responseMessage = await client.GetAsync
                                          ("http://jsonplaceholder.typicode.com/posts/1");

                    if (responseMessage.IsSuccessStatusCode)
                        ResponseText = await responseMessage.Content.ReadAsStringAsync();
                    else
                        ResponseText = $"StatusCode: {responseMessage.StatusCode}";
                }
            }
            catch (Exception exception)
            {
                ResponseText = exception.ToString();
            }
        }
    }
}

I like intellisense in designer so I'll add model into designer.

XML
<?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:models="clr-namespace:AsyncTest.Models;assembly=AsyncTest"
             x:Class="AsyncTest.MainPage">

    <ContentPage.BindingContext>
        <models:MainModel />
    </ContentPage.BindingContext>

    <ContentPage.Content>
        <Label Text="{Binding ResponseText}" />
    </ContentPage.Content>

</ContentPage>

And now we have to tell the model about this page so it'll initialize events.

C#
using AsyncTest.Models;

namespace AsyncTest
{
    public partial class MainPage
    {
        public MainPage()
        {
            InitializeComponent();
            ((BaseModel) BindingContext).Initialize(this);
        }
    }
}

That's it. Hit F5 and enjoy!

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)