Débutant Intermédiaire

MVVM Light Toolkit

mvvm-light-white
MVVM Light est un Framework qui permet d’accélérer le développement d’applications MVVM en WPF, Silverlight, Windows Phone (WP), Windows Store (RT) et même en Xamarin.

Ce Framework vous aide à séparer les différentes couches afin de créer des applications propres, facile à maintenir et à étendre. Ce qui rend vos applications facilement testables.

Nous allons, au travers de cet article, parcourir les différentes fonctionnalités offertes par ce Framework qui a réussi à se faire une place, parmi les meilleurs, en si peu de temps.

Introduction à MVVM

MVVM (Model, View, ViewModel) est une variation du pattern MVC, il permet de :

  • Créer des applications faciles à maintenir
  • Découpler les différentes couches d’une application
  • Faciliter les tests unitaires

mvvm
Le schéma ci-dessus représente les différentes couches d’une application basée sur le pattern MVVM, on y trouve principalement :

    • La Vue (View) : tout ce qui visuel, il se présente comme un fichier .xaml ayant une structure XML
    • Le Model : il représente les données de l’application, il peut être sous forme d’un DTO ou un fichier xml
    • Le ViewModel : c’est le contrôleur en MVC, il gère toutes les interactions entre la Vue et le Model

Installation

L’installation de MVVM Light peut se faire facilement à l’aide du package NuGet ou en utilisant la commande suivante : Install-Package MvvmLight
mvvm-ligh-nuget
A savoir qu’à partir de la version 5.0.0, MVVM Light supporte la plateforme Xamarin Android.

Cette installation va copier, automatiquement, 3 dll dans les références du projet en cours :

      • GalaSoft.MvvmLight.dll

Elle contient toutes les classes de base nécessaires à la création d’une application basée sur une architecture MVVM.

      • GalaSoft.MvvmLight.Extras.dll

Cette dll contient un IoC (SimpleIoc) créé spécifiquement pour MVVM Light. Vous n’êtes pas obligés de l’utiliser pour faire toute la mécanique d’injection de dépendances, car il peut être facilement remplacé par un autre outil, comme Funq (mon IoC préféré) par exemple.

      • GalaSoft.MvvmLight.Platform.dll

Cette librairie peut contenir des fonctionnalités différentes en fonction de la plateforme de développement utilisée (WPF, Windows Phone Silverlight, Windows Phone Apps, Windows Apps)

En plus de ces 3 dll, l’installation va aussi exécuter un script qui va créer un dossier ViewModel dans lequel elle va mettre deux classes :
MainViewModel.cs : Le ViewModel qui sera, souvent, utilisée avec la page principale du projet
ViewModelLocator.cs : Une classe utilisant SimpleIoc dont on va parler dans le chapitre suivant.

Enfin, le fichier App.xaml va être modifié afin de contenir une référence vers le ViewModelLocator

ViewModelLocator

Dans MVVM, la pratique habituelle est de faire en sorte que les vues (View) trouvent leurs ViewModel en les résolvants à partir d’un conteneur d’injection de dépendances (DI). Et ceci est fait automatiquement lorsque le conteneur est prié de fournir (résoudre) une instance de la vue.
Le conteneur injecte alors le ViewModel dans la View, en utilisant un constructeur de cette dernière qui accepte un ViewModel comme paramètre. Ce principe est appelé l’inversion de contrôle (Inversion of Control IoC).

L’avantage principal de l’injection de dépendances est la possibilité de configurer le conteneur au moment de l’exécution sur la manière dont les types seront résolus quand ils sont demandés, ce qui permet de faciliter les tests unitaires en utilisant des Mocks au lieu des vrais types.

Quand Laurent Bugnion a commencé à créer MVVM Light, il avait le choix entre l’utilisation d’un Framework d’injection de dépendances existant ou la création d’un nouveau IoC propre à MVVM Light. Et je pense que Laurent a fait le meilleur choix en décidant de créer SimpleIoc, car chaque développeur a ses propres préférences pour les IoC.

Enfin, le ViewModelLocator est une classe utilisant juste SimpleIoc pour assigner les implémentations à leurs interfaces et de les renvoyer à la demande. Chaque View instancie le ViewModelLocator comme une partie de ses ressources et lie son DataContext au ViewModel se trouvant dans le Locator.

Voici des exemples d’utilisation :

        • Assigner une classe à son interface
SimpleIoc.Default.Register();
        • Résoudre un objet à partir de son interface
SimpleIoc.Default.GetInstance();
        • Enregistrer un type concret
SimpleIoc.Default.Register();
        • Pour résoudre un objet directement
SimpleIoc.Default.GetInstance();

Pour lier une View à un ViewModel, on utilise la syntaxe suivante :

DataContext="{Binding Path=MainViewModel, Source={StaticResource ViewModelLocator}}"

ViewModelBase vs ObservableObject

Qui parle de MVVM parle forcément de l’interface INotifyPropertyChanged. Cette dernière permet d’effectuer la mécanique de notifications qui permet à la vue d’être informée de tous les changements sur la couche de présentation (ViewModel) ou, parfois, directement sur les données (Model).

Pour l’histoire : MVMM Light contenait à ses débuts la classe ViewModelBase qui implémentait directement l’interface INotifyPropertyChanged. Cette implémentation contient beaucoup de méthodes qui sont très utiles lorsqu’elles sont utilisées avec un ViewModel, mais qui étaient un peu lourde si utilisées avec un Model qui n’a besoin que de lever l’évènement PropertyChangedEventHandler.
Pour ne pas alourdir les objets (Model) avec des informations inutiles, la classe ObservableObject a été introduite. Cette classe implémente l’interface INotifyPropertyChanged et permet de lever l’évènement PropertyChangedEventHandler en cas d’une modification d’une propriété.

ViewModelBase hérite, maintenant, de la classe ObservableObject, implémente l’interface ICleanup et rajoute des informations primordiales pour une meilleure utilisation avec les ViewModels

PS : ObservableObject et ViewModelBase contiennent maintenant une méthode Set qui est très utile pour gérer les notifications. Son fonctionnement est le suivant :
Au lieu d’écrire à chaque fois les lignes suivantes :

set
{
    if(_name == value)
    {
        return;
    }

    _name = value;
    RaisePropertyChanged();
}

On peut l’écrire, maintenant, avec cette syntaxe :

set { Set(() => Name, ref _name, value); }

Cette méthode utilise EqualityComparer pour comparer les deux valeurs _name et value, modifie la valeur de la variable _name passée en référence (si les deux valeurs sont différentes) puis lève l’évènement PropertyChangedEventHandler.

RelayCommand

L’implémentation de l’interface ICommand dans MVVM Light est appelée RelayCommand.
Le constructeur de cette classe prend deux paramètres :
Action execute : L’action qui sera exécutée, elle peut être une méthode ou une expression Lambda
Func canExecute (optionnel) : Indique si l’action a exécuter est possible ou pas

Son utilisation est la suivante :

MyCommand = new RelayCommand(MyCommandExecute, () => _canExecuted);
private void MyCommandExecute() { }

On peut aussi utiliser les RelayCommand avec la syntaxe async/await de cette façon :

MyCommand = new RelayCommand(async () => { await MyCommandExecute });

Si vous avez besoin d’avoir plus d’informations sur les RelayCommands, veuillez consulter l’article de David Poulin sur le blog de SOAT.

EventToCommand

Comme son nom l’indique, la classe EventToCommand (un événement vers une commande) permet de lier n’importe quel événement à une commande. Prenons un exemple :

<DataTemplate x:Key="PersonDataTemplate">
    <StackPanel>
      <i:Interaction.Triggers>
        <i:EventTrigger EventName="Tap">
          <command:EventToCommand Command="{Binding MainViewModel.PersonDetailsCommand, Source={StaticResource ViewModelLocator}}"
                                  CommandParameter="{Binding}" />
        </i:EventTrigger>
      </i:Interaction.Triggers>
    </StackPanel>
</DataTemplate>

Ce morceau de code va nous nous permettre de lancer la commande ‘PersonDetailsCommand’ du ViewModel ‘MainViewModel’ au moment du déclenchement de l’événement ‘Tap’ et passera en paramètre l’élément touché.

A savoir que le “Behaviour SDK (XAML) for Visual Studio 2013” contient maintenant une classe appelée “InvokeCommandAction” se trouvant dans la dll ‘System.Windows.Interactivity’ et qui permet de faire exactement la même chose que le EventToCommand avec moins d’options, mais qui fonctionne très bien et permet de déplacer le DataTemplate dans un ResourceDictionary. Ce qui était la finalité initiale de cette classe !

Blendability

Dans la suite logique des différentes fonctionnalités offertes par MVVM Light, on trouve aussi la ‘Blendability’, qui consiste en la visualisation des données en cours de la conception (En anglais : design time data).

Cette fonctionnalité nous permet d’avoir un rendu de notre application avant même qu’elle ne soit lancée dans l’émulateur ou déployée sur un smartphone, ce qui facilite beaucoup le travail avec les interfaces utilisateurs (UI) pendant le développement.

MVVM Light introduit une propriété statique (IsInDesignMode) qui nous permet de savoir si on est en mode de design. Et grâce à cette propriété, on peut injecter des implémentations différentes en fonction de l’environnement sur lequel l’application est visualisée. (Dans le designer ou sur le téléphone).

Prenons le morceau de code suivant :

if (ViewModelBase.IsInDesignModeStatic)
{
    SimpleIoc.Default.Register();
}
else
{
    SimpleIoc.Default.Register();
}

Dans cet exemple, si on est en mode Design la classe DesignDataService sera assigné à l’interface IDataService. Avec cette manière, nous pouvons créer des (fausses) données qui seront utilisées pour visualiser ce que l’application peut donner s’elle est réellement exécutée sur un téléphone, ce dernier utilisera alors la vraie implémentation qui est la classe DataService.

Messenger

Ceux qui sont familiers avec le Framework Prism ont surement utilisé l’EventAggregator qui permet de faire communiquer des ‘Publisher’ (éditeur) et des “Subscribers” (abonnés) sans que ces composants possèdent de référence entre eux.

MVVM utilise le même principe avec la classe Messenger, qui a été développée en collaboration avec Glenn Block (l’un des développeurs de l’EventAggregator).

Prenons l’exemple suivant :
Dans la page principale d’une application, on possède un LongListSelector qui contient une liste de personnes. L’évènement ‘Tap’ sur une de ces personnes va déclencher la commande ‘PersonDetailsCommand’ qui exécutera la méthode ShowDetailsCommandExecute en passant en paramètre la personne sélectionnée. Dans cette méthode, on va naviguer via la page de détails et on va envoyer la personne reçue en paramètre en utilisant le Messenger.

private void ShowDetailsCommandExecute (object friend)
{
    _navigationService.NavigateTo(new Uri("/DetailsPage.xaml", UriKind.Relative))
    Messenger.Default.Send((Friend)friend);
}

Dans le constructeur du ViewModel, attaché à la page de détails d’une personne, on enregistre notre ‘Messenger’ pour recevoir tous les messages contenant un objet de type ‘IFriend’

public DetailsViewModel ()
{
    Messenger.Default.Register (
        this,
        true,
        TraiterMessage) ;
}

private void TraiterMessage(IFriend friend)
{
    ...
}

Messenger
Cette implémentation assez simple nous permet d’envoyer des messages sans aucun Feedback à toutes les pages qui se sont inscrites pour les recevoir. Et ceci est valable pour toute inscription qui implémente un objet de type IFriend.

Autre fonctionnalités

MVVM Light introduit à partir de la version 5.0 le support de Xamarin Forms qui permet le développement d’applications mobiles sur les plateformes Android et iOS. Jusqu’à maintenant, le Framework supporte :

  • Le Databinding
  • Les commandes
  • La Navigation & Dialog
  • Le Storyboarding en XAML

Laurent est très actif sur le développement de son Framework. Si vous souhaitez connaitre les nouveautés, n’hésitez pas à visiter régulièrement le site web dédié ou à aller directement sur la page de notes de version.

Dernier mot

Pour vous faciliter la compréhension de ce Framework, j’ai créé une application Windows Phone 8.1 (Silverlight) dans laquelle j’ai essayé de mettre en place toutes les notions abordées lors de cet article à savoir :

  • ViewModelLocator
  • ViewModelBase
  • ObservableObject
  • RelayCommand
  • EventToCommand & InvokeCommandAction
  • Blendability
  • Messenger

Le code source est consultable en ligne sur mon GitHub.

Pour découvrir toutes ces fonctionnalités en détail, vous pouvez consulter le nouveau tutoriel de Laurent Bugnion sur Plurasight.

Enfin une communauté très active existe sur ce sujet sur Stackoverflow et répond à toutes les questions relatives à MVVM Light.

Nombre de vue : 2252

AJOUTER UN COMMENTAIRE