L’architecture MVVM
MVVM Light Toolkit
Jean-Baptiste Vigneron
@jbvigneron
David Bottiau
@dbottiau
Sommaire
• Introduction
– Présentation
– MVVM Light Toolkit
– Comparaison rapide entre MVVM, MVC et MVP
• Notes pour cette...
Présentation
• MVVM est un patron de conception (design-pattern)
conçu à la base pour les applications .NET
• Model (Modèl...
MVVM Light Toolkit
• Framework libre et gratuit facilitant l’implémentation du pattern
MVVM
• Crée par Laurent Bugnion (Ga...
Comparaison rapide entre
MVVM, MVC et MVP
Architecture
• DataService
• Classes d’accès à une ressource externe (base de données,
webservice, flux JSON, flux RSS, et...
Architecture
• Une Vue = un ViewModel
• Un ViewModel peut être lié à plusieurs vues (mais pas l’inverse)
• Le ViewModel es...
Notes pour cette présentation
• Les exemples utilisés s’appuient sur un projet de
gestion de cave à vins réalisé avec WPF....
Exemple de Model
public class Vin
{
public string Nom { get; set; }
public string Appellation { get; set; }
public Region ...
Exemple de ViewModel
public interface IMainViewModel
{
public string Titre { get; set; }
public ObservableCollection<Vin> ...
Exemple de ViewModel
public class MainViewModel : ViewModelBase, IMainViewModel
{
public MainViewModel()
{
Vins = new Obse...
Composition du ViewModel
• Le ViewModel contient les données affichées dans la Vue
• Il permet de faire abstraction de la ...
Focus : Binder une donnée
public class MainViewModel : ViewModelBase, IMainViewModel
{
private string _titre;
public strin...
Focus : Binder une donnée
• Côté ViewModel:
• Pour une donnée, on crée un attribut privé et une propriété publique
• Dans ...
Focus : Binder une collection de données
public class MainViewModel : ViewModelBase, IMainViewModel
{
public MainViewModel...
Focus : Binder une collection de données
• Côté ViewModel:
• On utilise le type ObservableCollection<T> (et non List<T> ou...
Modes de binding
• OneWay
• TwoWay
• OneTime
• OneWayToSource
• Default
La destination est mise à jour lorsque la source e...
public class MainViewModel : ViewModelBase, IMainViewModel
{
public MainViewModel()
{
ChargerVinsCommand = new RelayComman...
• Côté ViewModel:
• Les actions métiers sont représentées par des méthodes (idéalement privées, mais il
se peut de devoir ...
Exemple d’une View
<Page x:Class="CaveAVins.View.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentat...
Info sur les commandes
• Tous les contrôles graphiques ne proposent pas d’attribut Command.
• Tous les évènements ne peuve...
Info sur les commandes
private void lstVins_SelectionChanged(object sender, EventArgs e)
{
IMainViewModel vm = (IMainViewM...
En bref sur les ViewModels…
• Le ViewModel est une adaptation du Modèle pour la Vue
• Un ViewModel comporte des données et...
ViewModelLocator
• Cette classe recense les ViewModels de notre
application
• Elle permet d’ailleurs un accès facile à nos...
ViewModelLocator
public class ViewModelLocator
{
static ViewModelLocator()
{
ServiceLocator.SetLocatorProvider(() => Simpl...
ViewModelLocator
• On initialise le ServiceLocator dans le constructeur statique
• On référence ensuite les ViewModels de ...
public class ViewModelLocator
{
public static IMainViewModel MainVM
{
get
{
return ServiceLocator.Current.GetInstance<IMai...
public class ViewModelLocator
{
public static void CleanMain()
{
SimpleIoc.Default.Unregister<IMainViewModel>();
SimpleIoc...
public class ViewModelLocator
{
public static void Cleanup()
{
CleanMain();
}
}
ViewModelLocator
Enfin, on peut créer une ...
Liaison couches Vue et ViewModel
• Pour lier les 2 couches, on utilise le ViewModelLocator. On le référence dans le
fichie...
Liaison couches Vue et ViewModel
• Une fois la declaration du Locator faite, on peut aller chercher le
ViewModel de notre ...
Les Design ViewModels
• Ces classes contiennent des jeux de données fictives.
• Ces données fictives sont affichées direct...
Les Design ViewModels
On peut référencer nos Design ViewModels dans le ViewModelLocator
à l’aide de la propriété IsInDesig...
Les Design ViewModels
• Exemple
public class MainDesignViewModel : MainViewModel
{
public MainDesignViewModel()
{
Vins = n...
Messagerie
• La messagerie est fournie par MVVM Light Toolkit
• Elle permet d’envoyer des messages entre les classes
• Un ...
Messagerie
public class ExempleViewModel : ViewModelBase, IExempleViewModel
public ExempleViewModel()
{
EnvoyerPagesComman...
Messagerie
public class MainWindow
public MainWindow()
{
InitializeComponent();
Messenger.Default.Register<string>(this, C...
Messagerie
• Pour qu’une classe reçoive un message, on utilise la méthode Register
• On utilise la méthode Unregister pour...
En résumé…
• MVVM = Model – View – ViewModel
• MVVM a été conçu pour faciliter la séparation entre la logique et l’afficha...
Pattern MVVM avec MVVM Light Toolkit
Pattern MVVM avec MVVM Light Toolkit
Prochain SlideShare
Chargement dans…5
×

Pattern MVVM avec MVVM Light Toolkit

4 650 vues

Publié le

Découvrez comment implémenter le pattern MVVM à l'aide du MVVM Light Toolkit

Publié dans : Technologie
0 commentaire
4 j’aime
Statistiques
Remarques
  • Soyez le premier à commenter

Aucun téléchargement
Vues
Nombre de vues
4 650
Sur SlideShare
0
Issues des intégrations
0
Intégrations
495
Actions
Partages
0
Téléchargements
158
Commentaires
0
J’aime
4
Intégrations 0
Aucune incorporation

Aucune remarque pour cette diapositive

Pattern MVVM avec MVVM Light Toolkit

  1. 1. L’architecture MVVM MVVM Light Toolkit Jean-Baptiste Vigneron @jbvigneron David Bottiau @dbottiau
  2. 2. Sommaire • Introduction – Présentation – MVVM Light Toolkit – Comparaison rapide entre MVVM, MVC et MVP • Notes pour cette présentation • Architecture • Les ViewModels – Données – Commandes – Modes de binding • Le ViewModelLocator • Les Design ViewModels • La Messagerie
  3. 3. Présentation • MVVM est un patron de conception (design-pattern) conçu à la base pour les applications .NET • Model (Modèle) – View (Vue) – ViewModel (Vue- Modèle) • Permet une separation entre le traitement des données et la façon dont elles sont affichées • Utilisation du principe de “binding” au maximum
  4. 4. MVVM Light Toolkit • Framework libre et gratuit facilitant l’implémentation du pattern MVVM • Crée par Laurent Bugnion (GalaSoft) • Utilisable avec: • WPF • Windows 10 • Xamarin • Silverlight • Site officiel: http://www.galasoft.ch/mvvm/ • Téléchargeable via NuGet
  5. 5. Comparaison rapide entre MVVM, MVC et MVP
  6. 6. Architecture • DataService • Classes d’accès à une ressource externe (base de données, webservice, flux JSON, flux RSS, etc…) • Model • Des classes simples (POCO) représentant les données • ViewModel • Des fichiers .cs • Vue • Des fichier .xaml et .xaml.cs
  7. 7. Architecture • Une Vue = un ViewModel • Un ViewModel peut être lié à plusieurs vues (mais pas l’inverse) • Le ViewModel est l’adaptation du modèle pour la vue. Son rôle est donc autre que celui du Contrôleur MVC. • Le ViewModel et la Vue sont liés en utilisant le binding • Liaison des contrôles d’affichage (ListBox/ComboBox/TextBox…) à des données • Liaison des contrôles d’action (Button/Image/Slider…) à des commandes
  8. 8. Notes pour cette présentation • Les exemples utilisés s’appuient sur un projet de gestion de cave à vins réalisé avec WPF. • Pour simplifier l’implémentation de MVVM, nous avons utilisé le framework MVVM Light Toolkit.
  9. 9. Exemple de Model public class Vin { public string Nom { get; set; } public string Appellation { get; set; } public Region Region { get; set; } public int Annee { get; set; } } La classe la plus simple possible (POCO)
  10. 10. Exemple de ViewModel public interface IMainViewModel { public string Titre { get; set; } public ObservableCollection<Vin> Vins { get; } public ICommand ChargerVinsCommand { get; } } Déclaration dans une interface Données Commandes
  11. 11. Exemple de ViewModel public class MainViewModel : ViewModelBase, IMainViewModel { public MainViewModel() { Vins = new ObservableCollection<Vin>(); ChargerVinsCommand = new RelayCommand(ChargerVins); } private string _titre; public string Titre { get { return _titre; } set { _titre = value; RaisePropertyChanged(); } } public ObservableCollection<Vin> Vins { get; private set; } public ICommand ChargerVinsCommand { get; private set; } private void ChargerVins() { WebserviceClient client = new WebServiceClient(); IList<Vin> vins = client.GetVins(); Vins.Clear(); foreach (var vin in vins) Vins.Add(vin); } } Implémentation Données Commandes Initialisation
  12. 12. Composition du ViewModel • Le ViewModel contient les données affichées dans la Vue • Il permet de faire abstraction de la manière dont elles sont présentées • On va agir directement sur les données et non plus sur les contrôles graphiques • Le ViewModel contient les commandes (actions métiers) de la Vue • Afficher ou modifier une donnée est une action métier • Lancer une animation ou masquer un contrôle n’en est pas une • Chaque classe ViewModel hérite de la classe ViewModelBase, provenant de MVVM Light Toolkit
  13. 13. Focus : Binder une donnée public class MainViewModel : ViewModelBase, IMainViewModel { private string _titre; public string Titre { get { return _titre; } set { _titre = value; RaisePropertyChanged(); } } }
  14. 14. Focus : Binder une donnée • Côté ViewModel: • Pour une donnée, on crée un attribut privé et une propriété publique • Dans le setter, on appelle la méthode RaisePropertyChanged. Cette méthode permet d’avertir la Vue que la donnée a été modifiée • RaisePropertyChanged est contenu dans la classe ObservableObject dont ViewModelBase hérite. Cette classe implémente l’interface INotifyPropertyChanged. • Côté Vue: • Veiller à ce que le mode de binding soit approprié pour le rafraîchissement des données.
  15. 15. Focus : Binder une collection de données public class MainViewModel : ViewModelBase, IMainViewModel { public MainViewModel() { Vins = new ObservableCollection<Vin>(); } public ObservableCollection<Vin> Vins { get; private set; } }
  16. 16. Focus : Binder une collection de données • Côté ViewModel: • On utilise le type ObservableCollection<T> (et non List<T> ou des T[]) • Cette classe implémente déjà INotifyPropertyChanged, ainsi que d’autres interfaces pour le rafraîchissement automatique des données. • Côté Vue: • Veiller à ce que le mode de binding soit approprié pour le rafraîchissement des données.
  17. 17. Modes de binding • OneWay • TwoWay • OneTime • OneWayToSource • Default La destination est mise à jour lorsque la source est mise à jour, mais pas l’inverse. La destination est mise à jour lorsque la source est modifiée et vice-versa. La destination prend en compte un seul changement de la source. Si la source est de nouveau mise à jour, la destination n’est pas actualisée. La source est mise à jour lorsque la destination est mise à jour mais pas l’inverse. Pas toujours disponible en fonction de la technologie (ex: Windows Phone) Utilise le comportement par défaut pour le contrôle concerné. (ex: OneWay pour Label et TwoWay pour TextBox) Source: donnée du ViewModel Destination: valeur du contrôle graphique de la vue
  18. 18. public class MainViewModel : ViewModelBase, IMainViewModel { public MainViewModel() { ChargerVinsCommand = new RelayCommand(ChargerVins); } public ICommand ChargerVinsCommand { get; private set; } private void ChargerVins() { Vins.Clear(); WebServiceClient client = new WebServiceClient(); foreach (Vin vin in client.GetVins()) { Vins.Add(vin); } } } Focus : Binder une commande
  19. 19. • Côté ViewModel: • Les actions métiers sont représentées par des méthodes (idéalement privées, mais il se peut de devoir les rendre publiques pour nos tests unitaires) • On lie ces méthodes à des commandes (objets de type ICommand) • Le constructeur de RelayCommand prend 1 ou 2 paramètres 1. Obligatoire : La méthode qui sera appelée lors du déclenchement de la commande 2. Facultatif : La méthode qui détermine si la commande peut être exécutée ou non • La méthode associée à la commande peut prendre un (et un seul) paramètre. On utilise pour celà la classe RelayCommand<T>. • Côté Vue: • Les contrôles graphiques sont bindés aux commandes à l’aide de l’attribut Command (et CommandParameter si un paramètre est passé) Focus : Binder une commande
  20. 20. Exemple d’une View <Page x:Class="CaveAVins.View.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Height="1024" Width="1280" Title="Accueil" DataContext="{Binding MainVM, Source={StaticResource Locator}}"> <Grid> <TextBox Text="{Binding Titre, Mode=TwoWay}" /> <ListBox ItemsSource="{Binding Vins, Mode=OneWay}" /> <Button Command="{Binding ChargerVinsCommand}" /> </Grid> </Page>
  21. 21. Info sur les commandes • Tous les contrôles graphiques ne proposent pas d’attribut Command. • Tous les évènements ne peuvent pas être traduits directement en commande (ex: SelectionChanged, IsEnabled, etc…). Heureusement, il existe deux alternatives. • 1. Utiliser un EventTrigger dans le XAML : <i:Interaction.Triggers> <i:EventTrigger EventName="SelectionChanged"> <command:EventToCommand Command="{Binding ChargerVinsCommand}" /> </i:EventTrigger> </i:Interaction.Triggers>
  22. 22. Info sur les commandes private void lstVins_SelectionChanged(object sender, EventArgs e) { IMainViewModel vm = (IMainViewModel)DataContext; vm.ChargerVinsCommand.Execute(null); } • Tous les contrôles graphiques ne proposent pas d’attribut Command. • Tous les évènements ne peuvent pas être traduits directement en commande (ex: SelectionChanged, IsEnabled, etc…). Heureusement, il existe deux alternatives. • 2. Créer un évènement et appeler la commande :
  23. 23. En bref sur les ViewModels… • Le ViewModel est une adaptation du Modèle pour la Vue • Un ViewModel comporte des données et des commandes • Un ViewModel hérite de ViewModelBase • ViewModelBase implémente INotifyPropertyChanged pour notifier la Vue qu’une donnée a été modifiée • Pour une donnée simple, on appelle RaisePropertyChanged • Pour les collections, on utilise les ObservableCollection<T> • Une commande peut prendre un (et un seul) paramètre. • Si on veut faire des tests unitaires, ceux-ci peuvent être faits sur la couche ViewModel.
  24. 24. ViewModelLocator • Cette classe recense les ViewModels de notre application • Elle permet d’ailleurs un accès facile à nos ViewModels • Elle permet de lier la couche Vue et ViewModel • , et permet d’y accéder facilement. • Elle recense également tous les Design ViewModels qui seront utilisés par Visual Studio et Blend. • Elle comporte également des méthodes pour décharger les ViewModels de la mémoire vive lorsque ceux-ci ne sont plus utilisés.
  25. 25. ViewModelLocator public class ViewModelLocator { static ViewModelLocator() { ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default); SimpleIoc.Default.Register<IMainViewModel, MainViewModel>(); } public static IMainViewModel MainVM { get { return ServiceLocator.Current.GetInstance<IMainViewModel>(); } } public static void CleanMain() { SimpleIoc.Default.Unregister<IMainViewModel>(); SimpleIoc.Default.Register<IMainViewModel, MainViewModel>(); } public static void Cleanup() { CleanMain(); } }
  26. 26. ViewModelLocator • On initialise le ServiceLocator dans le constructeur statique • On référence ensuite les ViewModels de notre application à l’aide de la classe SimpleIoC (fournie par MVVM Light Toolkit). public class ViewModelLocator { static ViewModelLocator() { ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default); SimpleIoc.Default.Register<IMainViewModel, MainViewModel>(); } }
  27. 27. public class ViewModelLocator { public static IMainViewModel MainVM { get { return ServiceLocator.Current.GetInstance<IMainViewModel>(); } } } ViewModelLocator On déclare ensuite une propriété statique pour chaque ViewModel afin d’y avoir un accès rapide depuis n’importe quelle autre classe, et notamment la couche Vue. Le ServiceLocator utilise des singletons. Si l’instance existe, elle est retournée sinon elle est créée puis retournée. Une exception est levée si le ViewModel n’a pas été enregistré au préalable
  28. 28. public class ViewModelLocator { public static void CleanMain() { SimpleIoc.Default.Unregister<IMainViewModel>(); SimpleIoc.Default.Register<IMainViewModel, MainViewModel>(); } } ViewModelLocator Lorsqu’un ViewModel n’est plus nécessaire, il faut le retirer de la mémoire. On crée une méthode de nettoyage, qui va désallouer le ViewModel de la mémoire, puis le re-préparer en cas de besoin. Il ne sera réinstancié que si la propriété MainVM est appelée de nouveau.
  29. 29. public class ViewModelLocator { public static void Cleanup() { CleanMain(); } } ViewModelLocator Enfin, on peut créer une méthode Cleanup qui appelle toutes les autres méthodes Clean. Elle peut être appelé lorsque on a besoin de réinitialiser l’application par exemple.
  30. 30. Liaison couches Vue et ViewModel • Pour lier les 2 couches, on utilise le ViewModelLocator. On le référence dans le fichier App.xaml • On déclare une ressource de type ViewModelLocator (nommée ici Locator) • Exemple d’App.xaml dans un projet WPF: <Application x:Class="CavesAVins.View.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:viewModel="clr-namespace:CaveAVins.ViewModel;assembly=CaveAVins.ViewModel" StartupUri="MainWindow.xaml"> <Application.Resources> <ResourceDictionary> <viewModel:ViewModelLocator x:Key="Locator" /> </ResourceDictionary> </Application.Resources> </Application>
  31. 31. Liaison couches Vue et ViewModel • Une fois la declaration du Locator faite, on peut aller chercher le ViewModel de notre page. • On lie le ViewModel à la propriété DataContext de la Vue <Page x:Class="CaveAVins.View.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Height="1024" Width="1280" Title="Accueil" DataContext="{Binding MainVM, Source={StaticResource Locator}}">
  32. 32. Les Design ViewModels • Ces classes contiennent des jeux de données fictives. • Ces données fictives sont affichées directement dans Visual Studio et Blend. • Une classe Design ViewModel hérite d’un ViewModel. Pour chaque ViewModel, on peut donc créer un Design ViewModel. • Ainsi, il est possible de créer le rendu (les templates) de son application avec des données fictives sans devoir lancer/debugger l’application.
  33. 33. Les Design ViewModels On peut référencer nos Design ViewModels dans le ViewModelLocator à l’aide de la propriété IsInDesignModeStatic de ViewModelBase. Cette propriété est disponible partout et tout le temps. public class ViewModelLocator { static ViewModelLocator() { ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default); if (ViewModelBase.IsInDesignModeStatic) { // Mode Design pour Visual Studio en Blend SimpleIoc.Default.Register<IMainViewModel, MainDesignViewModel>(); } else { // Mode Debug / Run SimpleIoc.Default.Register<IMainViewModel, MainViewModel>(); } } }
  34. 34. Les Design ViewModels • Exemple public class MainDesignViewModel : MainViewModel { public MainDesignViewModel() { Vins = new ObservableCollection { new Vin { Nom = “La Tour Carnet”, Appellation = “Haut-Médoc”, Region = Region.Bordeaux }, new Vin { Nom = “Merlot”, Annee = 2011, Region = Region.Rhone }, new Vin { Nom = “Cuvée-Silex”, Appellation = “Pouilly-Fumé”, Region = Region.Loire }, } } }
  35. 35. Messagerie • La messagerie est fournie par MVVM Light Toolkit • Elle permet d’envoyer des messages entre les classes • Un message est un objet de n’importe quel type • Elle permet, par exemple, d’envoyer des messages entre: • Un ViewModel et une Vue • Deux ViewModels • Deux classes quelconques • Ce mécanisme est une solution de contournement lorsqu’aucune autre ne permet de transmettre un objet d’une classe à un autre
  36. 36. Messagerie public class ExempleViewModel : ViewModelBase, IExempleViewModel public ExempleViewModel() { EnvoyerPagesCommand = new RelayCommand<string>(EnvoyerMessage); } public Icommand ChangerPagesCommand { get; private set; } public void EnvoyerMessage(string message) { MessengerInstance.Send(message); } } • Côté ViewModel: Envoi du message
  37. 37. Messagerie public class MainWindow public MainWindow() { InitializeComponent(); Messenger.Default.Register<string>(this, ChangerPage); } private void AfficherMessage(string message) { Messenger.Show(message); } } • Côté Vue: Abonnement à réception du message
  38. 38. Messagerie • Pour qu’une classe reçoive un message, on utilise la méthode Register • On utilise la méthode Unregister pour la désabonner de la messagerie • N’importe quelle classe peut envoyer des messages, tout comme n’importe quelle classe peut en recevoir • Vous ne pouvez envoyer qu’un seul message à la fois, mais un message peut être un objet de n’importe quel type • Contrôlez-bien si votre message doit être reçu par une ou plusieurs classes simultanément en utilisant : • Correctement les méthodes Register et Unregister. • Un token pour créer des canaux réservés et différencier les récepteurs
  39. 39. En résumé… • MVVM = Model – View – ViewModel • MVVM a été conçu pour faciliter la séparation entre la logique et l’affichage • MVVM utilise la puissance du mécanisme de binding (OneWay/TwoWay) • MVVM Light Toolkit facilite l’implémentation de MVVM dans une application • Un ViewModel comporte des données et des commandes • MVVM facilite les tests unitaires, puisque c’est la couche VM qui peut être testée • Le ViewModelLocator permet l’accès facile aux ViewModels et gère leur cycle de vie • Les Design ViewModels contiennent des données fictives qui sont directement affichées dans Visual Studio et Blend • La messagerie permet de transmettre des objets entre classes

×