Cet article a fait l'objet d'une traduction automatique.

Windows Phone

Créez des applications MVVM avec Xamarin et MvvmCross

Thomas LeBrun

Le Model-View-ViewModel (MVVM) s'élève à devenir le modèle de référence de choix pour n'importe quelle application XAML (Windows Presentation Foundation (WPF) et Silverlight, Windows 8, Windows Phone). Introduit au début de WPF, il sépare les préoccupations, testabilité et plus encore. La meilleure partie est que vous pouvez l'utiliser pour toute autre technologie, même ceux qui n'utilisent pas XAML. En effet, vous pouvez utiliser le modèle avec ASP.NET, avec JavaScript et bien plus encore.

Novell vous permet de développer des applications Android ou iOS en code c#. Ces applications viennent avec leurs propres modèles de développement, mais grâce à un cadre appelé MvvmCross, vous pouvez apporter le modèle MVVM à ces plateformes aussi bien. Dans cet article, je vais vous donner tout ce qu'il faut comprendre MvvmCross et comment l'utiliser dans vos applications Android et iOS.

Un coup de œil à MVVM

Il ya eu beaucoup d'articles couvrant MVVM ces derniers temps, alors je ne passe beaucoup de temps à examiner le modèle MVVM. Pour résumer, MVVM est composée de trois parties : le modèle (ce qui correspond aux données que vous voudrez afficher et manipuler sur l'écran), la vue (ce qui est le composant de présentation et de l'interface utilisateur) et le ViewModel (qui prendra le modèle et l'afficher sur la vue à l'aide de la liaison de données et réagira à l'intervention de l'utilisateur). Figure 1 une représentation graphique de MVVM.

Vue d'ensemble du modèle modèle-vue-ViewModel
Figure 1 Vue d'ensemble du modèle modèle-vue-ViewModel

Lors du développement avec les technologies Microsoft, il est facile de voir la réutilisabilité fournie par MVVM. Mais qu'en est-il des technologies non-Microsoft ? Quant à Android ? Qu'en est-il des iOS ?

Bien sûr, vous pouvez toujours implémenter vos propres motifs ou méthodologies, mais ceux ne pourraient pas fournir certaines des fonctionnalités plus puissantes du MVVM, telles que la liaison de données et la testabilité. L'un des plus grands avantages de MVVM suivant est les ViewModels sont facilement testable. Cela vous permet également de pousser le code multi-plateformes dans le ViewModel. Ce code serait autrement contenu dans une plateforme -­une classe spécifique, comme une manette de jeu.

Novell et MvvmCross « résoudre ce problème » et offrent une manière unifiée d'utiliser MVVM sur d'autres plateformes. Avant de regarder à l'aide de MVVM sur d'autres plateformes, je vais prendre un moment pour expliquer de Novell.

Novell pour Applications Android/iOS

Novell est un ensemble d'outils qui fournit le code compilé haute performance avec un accès complet à tous les API natives. Il vous permet de créer des applications natives avec expériences spécifiques au périphérique. Tout ce que vous pouvez faire en Objective-C ou Java, vous pouvez faire en c# avec Novell.

Alors que vous pouvez utiliser Novell Studio pour développer des applications, vous pouvez également utiliser Visual Studio et tous les autres outils que vous utilisez déjà pour développement c# aujourd'hui. Cela comprend Team Foundation Server (pour le contrôle de code source) et plug-ins comme Resharper, GhostDoc et ainsi de suite.

Du point de vue du développeur, Novell propose trois products—Xamarin.Mac principale, Xamarin.iOS (MonoTouch.dll) et Xamarin.Android (Mono.Android.dll). Toute la ces derniers sont développées Mono, la version open source de Microsoft .NET Framework. Mono a effectivement été créé par Miguel De Icaza, co-fondateur et actuel directeur technique de Novell.

Dans iOS, un compilateur dédié compile des applications écrites sur c# directement à du code natif ARM. Pour Android, le processus est similaire à l'exécution et la compilation .NET. Le code source est compilé en langage intermédiaire (IL). Lorsque le code s'exécute sur l'appareil, une deuxième compilation (jouée juste à temps) compile le code de langage intermédiaire en code natif. C'est logique, car les applications Android sont développées en Java, qui a une architecture interne similaire à l'architecture du .NET Framework. Vous pouvez voir une représentation visuelle du processus de compilation pour iOS et Android en Figure 2.

Compilation Native avec Novell
Figure 2 Compilation Native avec Novell

La plupart du temps, vous n'avez pas à vous soucier de la gestion de la mémoire, affectation des ressources et ainsi de suite car tout est géré par le runtime que fournit de Novell. Cependant, il ya des cas où il faut être conscient de ce qui se passe, tels que l'interopérabilité avec Objective-C. Cela pourrait créer conservent des cycles ou où votre classe managée encapsule effectivement certaines ressources coûteuses, comme UIImage sur iOS. Pour plus d'informations à ce sujet, voir bit.ly/1iRCIa2.

Il y a des considérations spéciales pour les applications iOS. Alors que le Studio de Novell sur un Mac fournit tout le nécessaire pour iOS devel­loppement, Visual Studio utilisateurs sur un PC seront toujours besoin d'un Mac avec outils Novell installés. Cela vous permet de compiler des applications sur le réseau et de tester sur l'iOS Simulator ou un appareil iOS.

Novell vous permet de construire les iOS et Android applications c# ou F #, mais en utilisant le schéma traditionnel de modèle-vue-contrôleur. Si vous souhaitez que la portabilité, de maintenabilité et de testabilité accrue, vous avez besoin d'un moyen d'amener le modèle MVVM dans ces plates-formes. Entrez MvvmCross.

MvvmCross pour les applications de Novell

MvvmCross est un logiciel libre, cadre MVVM multi-plateforme développé par Stuart Lodge. Il est disponible pour les applications Android et WPF, iOS, Windows 8, Windows Phone. MvvmCross apporte le modèle MVVM pour plates-formes où il a été précédemment indisponible, comme iOS et Android.

Il prend également en charge la liaison de données dans les vues. Il s'agit d'une fonctionnalité puissante qui fournit la grande séparation des préoccupations. La vue utilisera les ViewModels pour offrir des comportements appropriés dans l'application. MvvmCross localise même les ViewModels dans un projet dédié, ainsi vous pouvez facilement faire référence et les réutiliser dans d'autres.

C'est le point le plus important quand on parle de MvvmCross. En localisant les ViewModels dans une bibliothèque de classe Portable (PCL), vous pouvez les ajouter comme une référence à d'autres projets. Bien sûr, ce n'est pas le seul intéressant point de MvvmCross. Il y a également une architecture de plug-in, l'injection de dépendance (DI) et plus encore.

À l'aide de MvvmCross sur Android/iOS

À l'aide de MvvmCross est facile parce que c'est seulement quelques paquets NuGet que vous ajoutez à vos projets. Une fois que vous l'avez fait, il y a quelques pas mineurs, que vous devez prendre avant de lancer l'application. Les étapes varient un peu entre iOS et Android, mais ils sont assez similaires. Le projet Core contienne vos ViewModels et la classe App. Cela initialise les services et définit le ViewModel qui débutera le lancement :

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

Dans votre application Android ou d'iOS, vous devez créer un fichier Setup.cs. Ce sera le projet de base de référence et informer le runtime comment instancier l'application :

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

Si le fichier d'installation crée l'application utilisant le fichier app. Celui-ci indique au runtime de charger un ViewModel particulière au démarrage à l'aide de la méthode RegisterAppStart.

Chaque vue est spécifique à chaque application. Il s'agit de la seule partie qui change. Sur Android, la classe hérite de MvxActivity (type d'activité sur Android hérite de l'activité). Pour iOS, les points de vue héritent de MvxViewController (norme ViewController sur iOS héritent de UIViewController) :

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

MvvmCross a besoin de savoir le ViewModel auquel est associée une vue. Vous pouvez le faire par défaut grâce à la convention de nommage. Vous pouvez aussi facilement le modifier par la substitution de la propriété View de l'affichage ou à l'aide de la MvxViewForAttribute :

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

Sur iOS et Android, les vues sont conçus avec des approches différentes. Sur iOS, l'affichage est défini dans le code c#. Sur Android, vous pouvez également utiliser le code c#. Mieux encore, cependant, vous pouvez utiliser le AXML (un format XML utilisé pour décrire l'interface utilisateur sur Android). En raison de ces différences, les liaisons de données sont définis différemment sur chaque plate-forme.

Sur iOS, vous créez une BindingDescriptionSet pour représenter le lien entre la View et le ViewModel. Dans ce jeu, vous spécifiez quel contrôle que vous souhaitez lier à quelle propriété avant d'appliquer la liaison :

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();

Sur Android à l'aide de AXML, vous pouvez utiliser le nouvel attribut XML MvxBind pour exécuter la liaison de données :

<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" />

L'attribut MvxBind prend en paramètres qui spécifient la propriété du contrôle à lier et la propriété du ViewModel à utiliser comme source. Si vous êtes un développeur XAML, sachez que le mode de liaison MvvmCross est TwoWay par défaut. En XAML, le mode de liaison par défaut est OneWay. Le cadre de le MvvmCross comprend quelques attributs XML personnalisés disponibles dans Mvx­BindingAttributes.xml, comme vous pouvez le voir dans Figure 3.

Figure 3 contenu du fichier MvxBindingAttributes.xml

<?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>

Le contenu de ce fichier est simple, mais très important. Le fichier indique les attributs que vous pouvez utiliser dans les fichiers AXML. Ainsi, vous pouvez le voir dans une opération de liaison, vous pouvez utiliser les attributs MvxBind ou MvxLang. Vous pouvez également utiliser certains nouveaux contrôles (MvxImageView, MvxListView). Chacun d'eux a consacré des attributs personnalisés, comme vous pouvez le voir dans Figure 4.

Figure 4 nouveaux contrôles ont des attributs personnalisés

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

Cela devrait être familière aux développeurs XAML. Les propriétés ItemsSource et ItemClick sont liées à certaines propriétés de la source de données (le ViewModel dans ce cas). Le MvxItemTemplate définit l'interface pour chaque élément dans ListView.

Vous vous en doutez la syntaxe pour iOS être tout à fait différent, mais, en réalité, c'est en fait assez similaire. La syntaxe utilisée dans le fichier AXML, dénommée « Fluent » liaison, est simplement une liaison de format texte, que vous pouvez mapper à la version c# ainsi. La commande utilisée dans l'exemple précédent pour sélectionner un élément dans la liste est un objet ICommand :

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

L'implémentation de cette interface est fournie par MvvmCross à l'aide de la classe MvxCommand :

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

Un problème courant lorsque vous utilisez le modèle MVVM est conversion de types. Cela se produit lorsque vous définissez des propriétés à l'aide d'un type qui n'est pas directement consommable par l'interface utilisateur. Par exemple, vous pourriez avoir une propriété d'image comme un tableau d'octets, mais vous voulez l'utiliser pour la propriété source d'un contrôle image. En XAML, vous pouvez résoudre ce problème avec l'interface IValueConverter, qui mappe les valeurs entre la View et le ViewModel.

Le processus est assez similaire avec MvvmCross, grâce à l'interface IMvxValueConverter et ses deux méthodes Convert et ConvertBack. Cette interface vous permet d'effectuer des conversions similaires à XAML, mais avec un objectif de croix-technologie en tête. Gardez à l'esprit cette interface a le même inconvénient que XAML. Il prend un objet comme paramètre et retourne en tant que la valeur. Coulée est donc requise. Afin d'optimiser cela, MvvmCross vous propose la classe générique de MvxValueConverter, qui prend en paramètres pour l'entrée et les types de retour :

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);
  }
}

Référencement le convertisseur est facile. Dans iOS, utilisez la méthode WithConversion dans la syntaxe fluente :

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

Dans Android, référencez le convertisseur directement dans le fichier AXML :

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

Convertisseurs sont localisés par leurs noms à l'aide de la réflexion. Par défaut, le cadre va chercher n'importe quel type de contenant « convertisseur » dans le nom. Vous pouvez aussi manuellement inscrire des convertisseurs en substituant la méthode FillValueConverters dans la classe de programme d'installation.

MvvmCross fournit un DIcontainer simple et léger. Vous pouvez enregistrer des classes et des interfaces dans le conteneur à l'aide de plusieurs modèles, y compris un enregistrement singleton, une inscription dynamique et plus :

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

Résolution des types dans le conteneur peut arriver de deux façons. Tout d'abord, vous pouvez utiliser la méthode Mvx.Resolve de résoudre explicitement le type. Il prend également en charge les injecteur de constructeur, ce qui permet d'effectuer la réflexion et résoudre automatiquement les paramètres lors de la création de l'objet MvvmCross :

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

Vous pouvez utiliser l'injecteur de constructeur pour les services, mais aussi les ViewModels. Ceci est important à comprendre, car tous les services développés pour votre application dans le projet de base sont, par défaut, multi-plateforme.

Vous pouvez également exploiter des services qui semblent être multi-plateforme, mais pour quelle application sont spécifique à la plateforme. Par exemple, prendre une photo avec l'appareil photo, obtenant l'utilisateur coordonne, à l'aide d'une base de données et ainsi de suite. Avec injection de constructeur ViewModels peut recevoir une interface où l'application est spécifique à la plateforme.

Pour mieux définir ce mécanisme d'injection et de code spécifique à la plate-forme, MvvmCross fournit un système de plug-in. Le système vous permet de créer et d'injecter de nouvelles fonctionnalités en cours d'exécution. Chaque plug-in est un service, exposé par une interface qui possède une implémentation concrète fournie pour chaque plate-forme. Le système de plug-in enregistre l'interface et la mise en œuvre. Applications consomment les plug-ins avec DI. DI permet également aux développeurs de plug-in fournissent une implémentation simplifiée « se moquer » au cours de tests et de développement.

Du point de vue du développeur, écrire un plug-in est aussi simple que l'écriture d'une interface. Vous créez une classe qui implémente cette interface et un chargeur de plug-in. Le chargeur plug-in est une classe qui implémente l'interface IMvxPluginLoader. Il enregistre l'interface plug-in et la mise en œuvre (en utilisant Mvx.RegisterType) lorsque sa méthode EnsureLoaded est appelée.

Il y a beaucoup de plug-ins déjà disponibles. Ils vont proposent des fonctionnalités telles que l'accès aux fichiers, courrier électronique, conversion JSON et ainsi de suite. Vous pouvez trouver la plupart d'entre eux à l'aide de NuGet. Sachez que certains plug-ins ne comprennent pas les implémentations pour toutes les plates-formes. Faites attention à ce détail lorsque vous envisagez d'utiliser un plug-in. Même si un plug-in est manquant de soutien pour votre plate-forme, vous pouvez trouver plus facile de suivre le modèle et appliquer le programme manquant au lieu de créer un nouveau plug-in sur votre propre. Dans ce cas, envisagez de contribuer votre implémentation vers le plug-in propriétaire afin que d'autres peuvent également l'utiliser ainsi.

MvvmCross est un cadre précieux. Pensez-y lors du développement d'applications mobiles — même sur Android et iOS. Le modèle MVVM, couplé avec la liaison de données et de plug-ins, fournit un système puissant pour la création de code hautement maintenable et portable.


Thomas Lebrun est consultante chez Square infini, un partenaire de Microsoft de Français travaillant sur des technologies telles que Windows 8, Windows Phone, Windows Presentation Foundation (WPF), Silverlight, Surface et plus. Il a écrit deux livres sur WPF et le modèle MVVM. Il est également un conférencier lors d'événements communautaires. Vous pouvez le suivre est blog à blog.thomaslebrun.net et sur Twitter à twitter.com/thomas_lebrun.

Merci à l'expert technique Microsoft suivant d'avoir relu cet article : Jared Bienz