This site uses cookies for analytics, personalized content and ads. By continuing to browse this site, you agree to this use. Learn more
Microsoft Logo
Gray Pipe
  • Developer Network
    • Downloads
      • Visual Studio
      • SDKs
      • Trial software
    • Programs
      • Subscriptions
      • Students
      • ISV
      • Startups
      • Events
    • Community
      • Magazine
      • Forums
      • Blogs
      • Channel 9
    • Documentation
      • APIs and reference
      • Dev centers
      • Samples
      • Retired content
Developer Network Developer

Subscriber portal

Get tools
magazine
  • Issues and downloads
    • All issues
    • 2019
      • February 2019
      • January 2019
    • 2018
      • Connect(); 2018
      • December 2018
      • November 2018
      • October 2018
      • September 2018
      • August 2018
      • July 2018
      • June 2018
      • May 2018
      • April 2018
      • March 2018
      • February 2018
      • January 2018
    • 2017
      • Connect(); 2017
      • December 2017
      • November 2017
      • October 2017
      • September 2017
      • August 2017
      • July 2017
      • June 2017
      • May 2017
      • April 2017
      • March 2017
      • February 2017
      • January 2017
    • 2016
      • December 2016
      • Connect(); 2016
      • November 2016
      • October 2016
      • September 2016
      • August 2016
      • July 2016
      • June 2016
      • May 2016
      • April 2016
      • March 2016
      • February 2016
      • January 2016
    • 2015
      • December 2015
      • November 2015
      • Windows 10 issue
      • October 2015
      • September 2015
      • August 2015
      • July 2015
      • June 2015
      • May 2015
      • April 2015
      • March 2015
      • February 2015
      • January 2015
    • 2014
      • Special 2014
      • December 2014
      • November 2014
      • October 2014
      • September 2014
      • August 2014
      • July 2014
      • June 2014
      • May 2014
      • April 2014
      • March 2014
      • February 2014
      • January 2014
    • 2013
      • Government 2013
      • December 2013
      • November 2013
      • October 2013
      • September 2013
      • August 2013
      • July 2013
      • June 2013
      • May 2013
      • April 2013
      • March 2013
      • February 2013
      • January 2013
    • 2012
      • December 2012
      • November 2012
      • Windows 8
      • October 2012
      • September 2012
      • August 2012
      • July 2012
      • June 2012
      • May 2012
      • April 2012
      • March 2012
      • February 2012
      • January 2012
    • 2011
      • December 2011
      • November 2011
      • October 2011
      • September 2011
      • August 2011
      • July 2011
      • June 2011
      • May 2011
      • April 2011
      • March 2011
      • February 2011
      • January 2011
    • 2010
      • December 2010
      • November 2010
      • October 2010
      • September 2010
      • August 2010
      • July 2010
      • June 2010
      • May 2010
      • April 2010
      • March 2010
      • February 2010
      • January 2010
    • 2009
      • December 2009
      • November 2009
      • October 2009
      • September 2009
      • August 2009
      • July 2009
      • June 2009
      • May 2009
      • April 2009
      • March 2009
      • February 2009
      • January 2009
  • Subscribe
  • Submit article
search clear
We’re sorry. The content you requested has been removed. You’ll be auto redirected in 1 second.
Issues and downloads 2014 August 2014 Windows Phone - Build MVVM Apps with Xamarin and MvvmCross

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:

XML
Copy
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:

XML
Copy
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):

XML
Copy
[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:

XML
Copy
[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:

XML
Copy
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:

XML
Copy
<TextView xmlns:local="http://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
Copy
<?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
XML
Copy
<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:

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

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

XML
Copy
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:

XML
Copy
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:

XML
Copy
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:

XML
Copy
<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:

XML
Copy
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:

XML
Copy
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

 

MSDN Magazine Blog

 

More MSDN Magazine Blog entries >


Current Issue


February 2019

Browse All MSDN Magazines


Subscribe to MSDN Flash newsletter


Receive the MSDN Flash e-mail newsletter every other week, with news and information personalized to your interests and areas of focus.

Follow us
  • https://www.facebook.com/microsoftdeveloper
  • https://twitter.com/msdev
  • https://plus.google.com/111221966647232053570/
Sign up for the MSDN Newsletter
Is this page helpful?
Your feedback about this content is important.
Let us know what you think.
Additional feedback?
1500 characters remaining
Thank you!
We appreciate your feedback.

Dev centers

  • Windows
  • Office
  • Visual Studio
  • Microsoft Azure
  • More...

Learning resources

  • Microsoft Virtual Academy
  • Channel 9
  • MSDN Magazine

Community

  • Forums
  • Blogs
  • Codeplex

Support

  • Self support

Programs

  • BizSpark (for startups)
  • Microsoft Imagine (for students)
United States (English)
  • Newsletter
  • Privacy & cookies
  • Terms of use
  • Trademarks
logo © 2019 Microsoft