Share via



August 2014

Volume 29 Number 8

Windows Phone : Build MVVM Apps with Xamarin and MvvmCross

Thomas LeBrun | August 2014

The Model-View-ViewModel (MVVM) pattern stands to become the reference pattern of choice for any XAML (Windows Presentation Foundation [WPF], Windows 8, Windows Phone and Silverlight) application. Introduced at the beginning of WPF, it separates concerns, testability and more. The best part is you can use it for any other technologies, even those that don’t use XAML. Indeed, you can use the pattern with ASP.NET, with JavaScript and more.

Xamarin lets you develop Android or iOS applications in C# code. These applications come with their own development models, but thanks to a framework called MvvmCross, you can bring the MVVM pattern to these platforms as well. In this article, I’ll give you all you need to understand MvvmCross and how to use it in your Android and iOS applications.

A Quick Look at MVVM

There have been plenty of articles covering MVVM lately, so I won’t spend a lot of time reviewing the MVVM pattern. To summarize, MVVM is composed of three parts: the Model (which corresponds to the data you’ll want to display and manipulate on screen), the View (which is the presentation component and the UI) and the ViewModel (which will take the Model and display it on the View using data binding and will respond to user interaction). Figure 1 shows a graphical representation of MVVM.

Overview of the Model-View-ViewModel Pattern
Figure 1 Overview of the Model-View-ViewModel Pattern

When developing with Microsoft technologies, it’s easy to see the reusability provided by MVVM. But what about non-Microsoft technologies? What about Android? What about iOS?

Of course, you can still implement your own patterns or methodologies, but those might not provide some of the most powerful features of MVVM, such as data binding and testability. One of the biggest benefits of following MVVM is the ViewModels are easily testable. This also lets you push cross-platform code into the ViewModel. This code would otherwise be contained in a platform-­specific class, like a controller.

Xamarin and MvvmCross “solve” this and offer a unified way to use MVVM on other platforms. Before looking at using MVVM on other platforms, I’ll take a moment to explain Xamarin.

Xamarin for Android/iOS Applications

Xamarin is a set of tools that delivers high-performance compiled code with full access to all the native APIs. It lets you create native apps with device-specific experiences. Anything you can do in Objective-C or Java, you can do in C# with Xamarin.

While you can use Xamarin Studio to develop apps, you can also use Visual Studio and all the other tools you already use for C# development today. This includes Team Foundation Server (for the source control) and plug-ins such as Resharper, GhostDoc and so on.

From a developer’s perspective, Xamarin offers three main products—Xamarin.Mac, Xamarin.iOS (MonoTouch.dll) and Xamarin.Android (Mono.Android.dll). All of these are developed on top of Mono, the open source version of the Microsoft .NET Framework. Mono was actually initially created by Miguel De Icaza, the co-founder and current CTO of Xamarin.

In iOS, a dedicated compiler compiles applications written on C# directly to native ARM code. For Android, the process is similar to .NET compilation and execution. The sourcecode is compiled to an intermediate language (IL). When the code executes on the device, a second compilation (performed just in time) compiles the IL code to native code. This makes sense because Android applications are developed in Java, which has an internal architecture similar to the architecture of the .NET Framework. You can see a visual representation of the compilation process for iOS and Android in Figure 2.

Native Compilation with Xamarin
Figure 2 Native Compilation with Xamarin

Most of the time, you don’t have to worry about the memory management, resource allocation and so on because everything is managed by the runtime Xamarin provides. However, there are cases when you have to be aware of what’s happening, such as interop with Objective-C. This could create retain cycles or where your managed class actually wraps some expensive resources, such as UIImage on iOS. For more about this, see bit.ly/1iRCIa2.

There are special considerations for iOS applications. While Xamarin Studio on a Mac provides everything needed for iOS devel­opment, Visual Studio users on a PC will still need a Mac with Xamarin tools installed. This lets you compile applications over the network and test them on the iOS Simulator or an iOS device.

Xamarin lets you build iOS and Android applications using C# or F#, but using the traditional Model-View-Controller pattern. If you want increased testability, maintainability and portability, you need a way to bring the MVVM pattern to these platforms. Enter MvvmCross.

MvvmCross for Xamarin Apps

MvvmCross is an open source, cross-platform MVVM framework developed by Stuart Lodge. It’s available for Windows Phone, Windows 8, iOS, Android and WPF applications. MvvmCross brings the MVVM pattern to platforms where it was previously unavailable, like iOS and Android.

It also supports data binding in Views. This is a powerful feature that provides great separation of concerns. The View will use the ViewModels to offer proper behaviors in the application. MvvmCross even locates the ViewModels in a dedicated project so you can easily reference and reuse them in others.

This is the most important point when talking about MvvmCross. By locating the ViewModels in a Portable Class Library (PCL), you can add them as a reference to any other projects. Of course, that’s not the only interesting point of MvvmCross. There’s also a plug-in architecture, dependency injection (DI) and more.

Using MvvmCross on Android/iOS

Using MvvmCross is easy because it’s only a few NuGet packages you add to your projects. Once you’ve done this, there are a few minor steps you have to take before launching the application. The steps vary a bit between iOS and Android, but they’re quite similar. The Core project contains your ViewModels and the App class. This initializes the services and defines the ViewModel that will start on launch:

public class App : MvxApplication
{
  public override void Initialize()
  {
    this.CreatableTypes()
      .EndingWith("Service")
      .AsInterfaces()
      .RegisterAsLazySingleton();
    this.RegisterAppStart<HomeViewModel>();
  }
}

In your iOS or Android application, you have to create a Setup.cs file. This will reference the Core project and let the runtime know how to instantiate the application:

public class Setup : MvxAndroidSetup
{
  public Setup(Context applicationContext) : base(applicationContext)
  {
  }
  protected override IMvxApplication CreateApp()
  {
    return new Core.App();
  }
}

So the setup file creates the application using the app file. The latter one indicates to the runtime to load a particular ViewModel upon startup using the RegisterAppStart method.

Each view is specific to each application. This is the only part that changes. On Android, the class inherits from MvxActivity (standard activities on Android inherit from Activity). For iOS, the Views inherit from MvxViewController (standard ViewController on iOS inherit from UIViewController):

[Activity(ScreenOrientation = ScreenOrientation.Portrait)]
public class HomeView : MvxActivity
{
  protected override void OnViewModelSet()
  {
    SetContentView(Resource.Layout.HomeView);
  }
}

MvvmCross needs to know the ViewModel with which a View is associated. You can do this by default thanks to the naming convention. You can also easily change it by overriding the ViewModel property of the View or using the MvxViewForAttribute:

[Activity(ScreenOrientation = ScreenOrientation.Portrait)]
[MvxViewFor(typeof(HomeViewModel))]
public class HomeView : MvxActivity
{ ... }

On iOS and Android, the Views are designed with different approaches. On iOS, the View is defined in C# code. On Android, you can also use C# code. Even better, though, you can use the AXML format (an XML format used to describe the UI on Android). Because of these differences, data bindings are defined differently on each platform.

On iOS, you create a BindingDescriptionSet to represent the link between the View and the ViewModel. In that set, you specify which control you want to bind to which property before applying the binding:

var label = new UILabel(new RectangleF(10, 10, 300, 40));
Add(label);
var textField = new UITextField(new RectangleF(10, 50, 300, 40));
Add(textField);
var set = this.CreateBindingSet<HomeView, 
  Core.ViewModels.HomeViewModel>();
set.Bind(label).To(vm => vm.Hello);
set.Bind(textField).To(vm => vm.Hello);
set.Apply();

On Android using AXML, you can use the new XML attribute MvxBind to perform the data binding:

<TextView xmlns:local="https://schemas.android.com/apk/res-auto"
          android:text="Text"
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:id="@+id/tripitem_title"
          local:MvxBind="Text Name"
          android:gravity="center_vertical"
          android:textSize="17dp" />

The MvxBind attribute takes in parameters that specify the property of the control to bind and the property of the ViewModel to use as the source. If you’re a XAML developer, be aware that the MvvmCross binding mode is TwoWay by default. In XAML, the default binding mode is OneWay. The MvvmCross Framework understands a few custom XML attributes available in Mvx­BindingAttributes.xml, as you can see in Figure 3.

Figure 3 Contents of the MvxBindingAttributes.xml File

<?xml version="1.0" encoding="utf-8"?>
<resources>
  <declare-stylable name="MvxBinding">
    <attr name="MvxBind" format="string"/>
    <attr name="MvxLang” format="string"/>
  </declare-styleable>
  <declare-stylable name="MvxControl">
    <attr name="MvxTemplate" format="string"/>
  </declare-styleable>
  <declare-styleable name="MvxListView">
    <attr name="MvxItemTemplate" format= "string"/>
    <attr name="MvxDropDownItemTemplate" format="string"/>
  </declare-stylable>
  <item type="id" name="MvxBindingTagUnique">
  <declare-styleable name="MvxImageView">
    <attr name="MvxSource" format="string"/>
  </declare-stylable>
</resources>

The contents of this file are simple, but very important. The file indicates the attributes you can use in the AXML files. So, you can see in a binding operation, you can use MvxBind or MvxLang attributes. You can also use some new controls (MvxImageView, MvxListView). Each of them has dedicated custom attributes, as you can see in Figure 4.

Figure 4 New Controls Have Custom Attributes

<LinearLayout
  android:orientation="horizontal"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  android:layout_weight="2">
  <Mvx.MvxListView
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    local:MvxBind="ItemsSource Trips;ItemClick SelectTripCommand"
    local:MvxItemTemplate="@layout/tripitemtemplate" />
</LinearLayout>

This should be familiar to XAML developers. The ItemsSource and ItemClick properties are bound to some properties of the data source (the ViewModel in this case). The MvxItemTemplate defines the interface for each item in the ListView.

You might expect the syntax for iOS to be quite different, but, in reality, it’s actually quite similar. The syntax used in the AXML file, referred to as “Fluent” binding, is simply a text-format binding you can map to the C# version as well. The command used in the previous example to select an item on the list is an ICommand object:

public ICommand<Trip> SelectTripCommand { get; set; }

The implementation of this interface is provided by MvvmCross using the MvxCommand class:

private void InitializeCommands()
{
  this.SelectTripCommand = new MvxCommand<Trip>(
    trip => this.ShowViewModel<TripDetailsViewModel>(trip),
    trip => this.Trips != null && this.Trips.Any() && trip != null);
}

A common problem when using the MVVM pattern is converting types. This happens when you define properties using a type that isn’t directly consumable by the UI. For example, you might have an image property as a byte array but you want to use it for the source property of an image control. In XAML, you can solve this problem with the IValueConverter interface, which maps values between the View and the ViewModel.

The process is quite similar with MvvmCross, thanks to the IMvxValueConverter interface and its two methods Convert and ConvertBack. This interface lets you perform conversions similar to XAML, but with a cross-technology objective in mind. Keep in mind this interface has the same drawback as XAML. It takes an object as a parameter and returns it as the value. So casting is required. To optimize this, MvvmCross offers the generic MvxValueConverter class, which takes in parameters for the input and the return types:

public class ByteArrayToImageConverter : 
  MvxValueConverter<byte[], Bitmap>
{
  protected override Bitmap Convert(byte[] value, Type targetType,
    object parameter, CultureInfo culture)
  {
    if (value == null)
        return null;
    var options = new BitmapFactory.Options { InPurgeable = true };
    return BitmapFactory.DecodeByteArray(value, 
      0, value.Length, options);
  }
}

Referencing the converter is easy. In iOS, use the method WithConversion in the fluent syntax:

var set = this.CreateBindingSet<HomeView, 
  Core.ViewModels.HomeViewModel>();
set.Bind(label).To(vm => vm.Trips).WithConversion("ByteArrayToImage");
set.Apply();

In Android, reference the converter directly in the AXML file:

<ImageView
  local:MvxBind="Bitmap Image,Converter=ByteArrayToImage"
  android:layout_width="fill_parent"
  android:layout_height="wrap_content" />

Converters are located by their names using reflection. By default, the framework will search for any type containing “converter” in the name. You can also manually register converters by overriding the FillValueConverters method in the Setup class.

MvvmCross provides a simple and light DIcontainer. You can register classes and interfaces in the container using multiple patterns including a singleton registration, a dynamic registration and more:

Mvx.RegisterType<ISQLiteConnectionFactory, SQLiteConnectionFactory>();
Mvx.RegisterSingletong<ISQLiteConnectionFactory, SQLiteConnectionFactory>();

Resolving types in the container can happen two ways. First, you can use the Mvx.Resolve method to explicitly resolve the type. It also supports constructor injection, which lets MvvmCross perform reflection and automatically resolve parameters during object creation:

private readonly ISQLiteConnectionFactory _sqlFactory;
public DataAccessLayerService(ISQLiteConnectionFactory sqlFactory)
{
  this._sqlFactory = sqlFactory;
}

You can use constructor injection for services, as well as ViewModels. This is important to understand because any services developed for your application put in the Core project are, by default, cross-platform.

You can also leverage services that seem to be cross-platform, but for which implementation is platform-specific. For example, taking a picture with the camera, getting the user coordinates, using a database and so on. With constructor injection, ViewModels can receive an interface where the implementation is platform-specific.

To further define this mechanism of injection and platform-specific code, MvvmCross provides a plug-in system. The system lets you create and inject new features at run time. Each plug-in is a service, exposed by an interface, which has a concrete implementation provided for each platform. The plug-in system registers the interface and implementation. Applications consume the plug-ins with DI. DI also lets plug-in developers provide a simplified “mock” implementation during testing and development.

From a developer’s point of view, writing a plug-in is as simple as writing an interface. You create a class that implements that interface and a plug-in loader. The plug-in loader is a class that implements the IMvxPluginLoader interface. It registers the plug-in interface and implementation (using Mvx.RegisterType) when its EnsureLoaded method is called.

There are many plug-ins already available. They’ll provide features such as file access, e-mail, JSON conversion and so on. You can find most of them using NuGet. Be aware that some plug-ins don’t include implementations for all platforms. Pay attention to this detail when planning to leverage a plug-in. Even if a plug-in is missing support for your platform, you may find it easier to follow the pattern and implement the missing platform instead of creating a new plug-in on your own. If this happens, consider contributing your implementation back to the plug-in owner so others can also use it as well.

MvvmCross is a valuable framework. Consider this when developing mobile applications—even on Android and iOS. The MVVM pattern, coupled with data binding and plug-ins, provides a powerful system for creating highly maintainable and portable code.


Thomas Lebrun is a consultant at Infinite Square, a French Microsoft partner working on technologies such as Windows 8, Windows Phone, Windows Presentation Foundation (WPF), Silverlight, Surface and more. He has written two books about WPF and the MVVM pattern. He’s also a regular speaker at community events. You can follow him on is blog at blog.thomaslebrun.net and on Twitter at twitter.com/thomas_lebrun.

Thanks to the following Microsoft technical expert for reviewing this article: Jared Bienz