Utiliser un modèle-vue

Effectué

Après avoir découvert les composants qui composent le modèle MVVM, vous avez probablement constaté que le modèle et la vue étaient faciles à définir. Examinons comment utiliser le modèle-vue pour mieux définir son rôle dans le schéma.

Exposer des propriétés à l’interface utilisateur

Comme dans l’exemple précédent, les modèles-vues s’appuient généralement sur des modèles pour la plupart de leurs données et une logique métier. Mais c’est le modèle-vue qui met en forme, convertit et enrichit les données en fonction des besoins de la vue actuelle.

Effectuer une mise en forme à l’aide d’un modèle-vue

Vous avez déjà vu un exemple de mise en forme des jours de congés. La mise en forme de données, le codage de caractères et la sérialisation sont tous des exemples de mise en forme des données par le modèle-vue d’après le modèle.

Effectuer une conversion à l’aide d’un modèle-vue

Souvent, le modèle fournit des informations de manière indirecte. Mais le modèle-vue peut les corriger. Par exemple, supposons que vous voulez indiquer à l’écran si un employé est superviseur. Mais notre modèle Employee ne nous indique pas cela directement. Seul le fait que des personnes sont éventuellement subordonnées à cet employé peut vous fournir cette information. Supposons que le modèle a cette propriété :

public IList<Employee> DirectReports
{
    get
    {
        ...
    }
}

Si la liste est vide, vous pouvez en déduire que Employee n’est pas superviseur. Dans ce cas, EmployeeViewModel inclut la propriété IsSupervisor qui fournit cette logique :

public bool IsSupervisor => _model.DirectReports.Any();

Effectuer un enrichissement à l’aide d’un modèle-vue

Parfois, un modèle peut fournir uniquement un ID pour les données associées. Ou bien, vous pouvez être amené à accéder à plusieurs classes de modèle pour mettre en corrélation les données requises pour un seul écran. Le modèle-vue fournit un emplacement idéal pour effectuer ces tâches en même temps. Supposons que vous voulez afficher tous les projets dont un employé s’occupe actuellement. Ces données ne font pas partie de la classe de modèle Employee. Elles sont accessibles par le biais de la classe de modèle CompanyProjects. Notre EmployeeViewModel, comme toujours, expose son travail sous forme de propriété publique :

public IEnumerable<string> ActiveProjects => CompanyProjects.All
    .Where(p => p.Owner == _model.Id && p.IsActive)
    .Select(p => p.Name);

Utiliser des propriétés directes avec un modèle-vue

Souvent, un modèle-vue a exactement besoin de la propriété fournie par le modèle. Pour ces propriétés, le ViewModel transmet simplement les données directement :

public string Name
{
    get => _model.Name;
    set => _model.Name = value;
}

Définir l’étendue du ViewModel

Vous pouvez utiliser un modèle-vue à tout niveau où il existe une vue. Une page a généralement un modèle-vue, tout comme les sous-vues de la page. Il est courant d’imbriquer des modèles-vues quand la page affiche un ListView sur la page. La liste a un modèle-vue qui représente la collection, telle que EmployeeListViewModel. Chaque élément de la liste est un EmployeeViewModel.

Diagramme d’un EmployeeListViewModel avec plusieurs sous-objets EmployeeViewModel.

Il est également courant d’avoir un ViewModel de niveau supérieur qui contient les données et l’état de l’application entière, mais qui n’est pas associé à une page en particulier. Un modèle-vue de ce type est couramment utilisé quand il s’agit de maintenir l’élément « actif ». Prenez en compte l’exemple ListView décrit précédemment. Quand l’utilisateur sélectionne une ligne d’employé, cet employé représente l’élément actuel. Si l’utilisateur accède à une page de détails ou sélectionne un bouton de barre d’outils pendant que cette ligne est sélectionnée, l’action ou l’affichage doit concerner cet employé. Une gestion élégante de ce scénario consiste à lier les données de ListView.SelectItem à une propriété à laquelle la barre d’outils ou la page de détails peuvent également accéder. Placer cette propriété sur un ViewModel central fonctionne bien.

Déterminer quand réutiliser des ViewModel avec des vues

La manière de définir la relation entre le modèle-vue et le modèle ainsi qu’entre le modèle-vue et la vue dépend davantage des exigences de l’application que de règles. L’objectif du modèle-vue est de fournir à la vue la structure et les données dont elle a besoin. Ce sont ces éléments qui doivent orienter les décisions liées à la définition de l’étendue d’un modèle-vue.

Les modèles-vues reflètent souvent étroitement la structure d’une classe de modèle et ont une relation un-à-un avec cette classe. Vous avez vu plus tôt un exemple avec le EmployeeViewModel qui wrappait et augmentait une instance Employee unique. Mais il ne s’agit pas toujours d’une relation un-à-un. Si le modèle-vue est conçu pour fournir ce dont la vue a besoin, vous pouvez finir avec quelque chose comme un HRDashboardViewModel pour fournir une vue d'ensemble d’un département de ressources humaines, qui n’a aucune relation explicite avec un modèle mais qui peut utiliser les données de n’importe quelle classe de modèle.

De même, vous pouvez constater que les modèles-vues et les vues ont souvent une relation un-à-un. Mais ce n’est pas nécessairement le cas. Reconsidérons un ListView qui présente une ligne pour chaque employé. Quand vous sélectionnez une des lignes, vous accédez à la page de détails d’un employé.

La page de la liste comporte son ViewModel avec une collection. Comme suggéré précédemment, cette collection peut être une collection d’objets EmployeeViewModel. Quand l’utilisateur sélectionne une ligne, l’instance EmployeeViewModelpeut être passée à EmployeeDetailPage. Et la page de détails peut utiliser EmployeeViewModel comme BindingContext.

Ce scénario peut être une excellente opportunité de réutilisation du modèle-vue. Mais gardez à l’esprit que les modèles-vues sont conçus pour fournir ce dont la vue a besoin. Dans certains cas, vous pouvez avoir besoin de modèles-vues distincts même si ceux-ci se basent tous sur la même classe de modèle. Dans cet exemple, les lignes ListView ont probablement besoin de beaucoup moins d’informations que la page de détails complète. Si la récupération des données requises par la page de détails ajoute une charge importante, vous pouvez envisager d’avoir les deux modèles EmployeeListRowViewModel et un EmployeeDetailViewModel servant ces vues respectives.

Modèle objet du modèle-vue

L’utilisation d’une classe de base qui instaure INotifyPropertyChanged signifie que vous n’avez pas besoin de réinstaurer l’interface sur chaque modèle-vue. Prenez en compte l’application RH comme décrit dans la partie précédente de ce module de formation. La classe EmployeeViewModel a instauré l’interface INotifyPropertyChanged et fourni une méthode d’assistance nommée OnPropertyChanged pour déclencher l’événement PropertyChanged. D’autres modèles-vue dans le projet, comme ceux qui décrivent les ressources affectées à un employé, nécessitent également des INotifyPropertyChanged pour entièrement s’intégrer à une vue.

La bibliothèque MVVM Toolkit qui fait partie du Kit de ressources communauté .NET, est un ensemble de types standard, autonomes et légers, qui fournissent une implémentation de démarrage pour la création d’applications modernes à l’aide du modèle MVVM.

Au lieu d’écrire votre propre classe de base de modèle-vue, vous héritez de la classe ObservableObject du kit de ressources, qui fournit tout ce dont vous avez besoin pour une classe de base de modèle-vue. Le nom EmployeeViewModel peut être une version simplifié de :

using System.ComponentModel;

public class EmployeeViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler? PropertyChanged;
    private Employee _model;

    public string Name
    {
        get {...}
        set
        {
            _model.Name = value;
            OnPropertyChanged(nameof(Name))
        }
    }

    protected void OnPropertyChanged(string propertyName) =>
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}

Par le code suivant :

using Microsoft.Toolkit.Mvvm.ComponentModel;

public class EmployeeViewModel : ObservableObject
{
    private string _name;

    public string Name
    {
        get => _name;
        set => SetProperty(ref _name, value);
    }
}

Le kit de ressources MVVM est distribué via le package NuGet CommunityToolkit.Mvvm.

Contrôle de vos connaissances

1.

Quand vous utilisez le modèle MVVM avec .NET MAUI, votre modèle, votre vue et votre modèle-vue ne sont pas complètement découplés les uns des autres. Parmi les choix suivants, lequel décrit une dépendance courante entre les éléments MVVM ?

2.

Pour quel élément la probabilité d’être étroitement couplé avec la plateforme et la difficulté de créer des tests unitaires sont-elles les plus grandes ? Le modèle, la vue ou le modèle-vue ?