MVVM simplement – 3ème partie

Les mécanismes de binding sont désormais bien présents.

Enfin, je vais implémenter le design pattern MVVM pour lequel je ne pourrais que vous conseillez cette bonne lecture en Français “MVVM de la découverte à la maîtrise”  des grands gourous Jonathan Antoine et Thomas Lebrun.

Je rappelle l’objectif très rapidement, obtenir 3 couches indépendantes les unes des autres pouvant être modifiées, changées  à souhait sans rien casser à l’application.

D’abord, j’installe “MVVM Light”, le framework MVVM le plus répandu par nuget.

Ensuite, je structure la solution afin de séparer les 3 couches Model-View-ViewModel en créant des dossiers du même nom (“MVVM Light” m’aide un peu en créant le ViewModel).

Je déplace la classe Person dans le dossier Model et le fichier xaml dans le dossier View. Jusqu’ici rien de transcendant, mais déjà ça présente mieux.

Pour créer notre ViewModel, il suffit de copier le code du code-behind (excepté le code lié au événements de ma View) vers notre classe MainViewModel. Ensuite, pour lier la View au ViewModel, je vais modifier le DataContext.

Simplement, il est possible d’instancier le ViewModel dans la vue comme suit mais la liaison est forte car la View instancie directement un ViewModel donné.

<Window.Resources>
        <viewModel:MainViewModel x:Key="ViewModel"/>
    </Window.Resources>
    <Grid DataContext="{Binding Source={StaticResource ViewModel}}">

Pour que le couplage entre les couches View et ViewModel soit faible, “MVVM Light” met en oeuvre l’inversion de contrôle qui permet d’obtenir une instance d’un objet à partir de son type. C’est ce que fait le ViewModelLocator.

using GalaSoft.MvvmLight.Ioc;
using Microsoft.Practices.ServiceLocation;
 
namespace MvvmForDummiesPart3.ViewModel
{
    public class ViewModelLocator
    {
        public ViewModelLocator()
        {
            ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
            SimpleIoc.Default.Register<MainViewModel>();
        }
 
        public MainViewModel Main
        {
            get
            {
                return ServiceLocator.Current.GetInstance<MainViewModel>();
            }
        }
    }
}

Dans le constructeur du ViewModelLocator, un composant d’inversion de contrôle est défini, puis le type MainViewModel est enregistré. La propriété Main permet d’obtenir une instance de MainViewModel.

L’objet Locator est instancié comme ressource globale de l’application dans App.xaml.

<Application.Resources>
    <vm:ViewModelLocator x:Key="Locator" d:IsDataSource="True" xmlns:vm="clr-namespace:MvvmForDummiesPart3.ViewModel" />
  </Application.Resources>

Il est ensuite utilisé dans la View et permet d’accèder à la propriété Main qui est utilisée dans le DataContext pour lier la View au ViewModel.

<Window x:Class="MvvmForDummiesPart3.View.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Calc your BMI" Height="480" Width="525"
        DataContext="{Binding Main, Source={StaticResource Locator}}">

Enfin, pour que les méthodes liées aux événements de ma vue (ici que des clics sur des boutons) soient appelées, nous allons utiliser les RelayCommand de “MVVM Light”, celles-ci sont déclarées dans le ViewModel et seront facilement liées au xaml (ce n’est pas souvent aussi facile !) car l’objet Button a une propriété Command. RelayCommand et Button implémentent tous les deux ICommand.

Ci-dessous, la déclaration des commandes, leur instanciation avec la méthode appelée dans le constructeur.

public RelayCommand NewPersonCommand { get; private set; }
        public RelayCommand CreatePersonCommand { get; private set; }
        public RelayCommand UpdatePersonCommand { get; private set; }
        public RelayCommand DeletePersonCommand { get; private set; }
        public RelayCommand CalcBmiCommand { get; private set; }
    
        public MainViewModel()
        {
            NewPersonCommand = new RelayCommand(NewPerson);
            CreatePersonCommand = new RelayCommand(CreatePerson);
            UpdatePersonCommand = new RelayCommand(UpdatePerson);
            DeletePersonCommand = new RelayCommand(DeletePerson);
            CalcBmiCommand = new RelayCommand(CalcBmi);
            Persons = new ObservableCollection<Person>();
            LoadPersons();
        }

Et voilà une application MVVM bien structurée et facile à maintenir: une couche View sans code-behind mais ce n’est en aucun cas une obligation (certaines interactions peuvent sans problème s’y trouver), une couche Model et une couche intermédiaire ViewModel.

Le code source de cette partie est disponible ici. Cette série d’article n’est pas terminée et j’expliquerai bientôt comment isoler les traitements “métier” de notre application dans des composants distincts du ViewModel.

December 30, 2017

Tags: ,

Leave a Reply

Your email address will not be published. Required fields are marked *