Partager via


Implémenter MVVM avec le kit de ressources MVVM

Maintenant que vous disposez de la structure du projet, vous pouvez commencer à implémenter le modèle MVVM à l’aide du kit de ressources MVVM. Cette étape implique la création de ViewModels qui tirent parti des fonctionnalités du kit de ressources MVVM, telles que ObservableObject la notification de modification de propriété et RelayCommand l’implémentation de commandes.

Installer le package NuGet du kit de ressources MVVM

Vous devez installer le kit de ressources MVVM dans les projets WinUINotes et WinUINotes.Bus .

Utilisation de Visual Studio

  1. Cliquez avec le bouton droit sur le projet WinUINotes.Bus dans l’Explorateur de solutions.
  2. Sélectionnez Gérer les packages NuGet.
  3. Recherchez CommunityToolkit.Mvvm et installez la dernière version stable.
  4. Répétez ces étapes pour le projet WinUINotes .

Utilisation de l’interface CLI .NET

Vous pouvez également utiliser l’interface CLI .NET pour installer le package :

dotnet add WinUINotes.Bus package CommunityToolkit.Mvvm
dotnet add WinUINotes package CommunityToolkit.Mvvm

Décisions de conception pour la couche de modèle

Lorsque vous implémentez MVVM, il est important de décider comment structurer vos classes de modèle par rapport aux ViewModels. Dans ce tutoriel, les classes de modèle (Note et AllNotes) sont responsables de la représentation des données, de la logique métier et de la mise à jour du stockage des données. Les ViewModels gèrent les propriétés observables, la notification de modification et les commandes pour l’interaction de l’interface utilisateur.

Dans une implémentation plus simple, vous pouvez utiliser des objets CLR simples (POCO) pour les classes de modèle sans aucune logique métier ou méthodes d’accès aux données. Dans ce cas, les ViewModels gèrent toutes les opérations de données via la couche de service. Toutefois, pour ce didacticiel, les classes de modèle incluent des méthodes de chargement, d’enregistrement et de suppression de notes pour fournir une séparation plus claire des préoccupations et garder les ViewModels concentrés sur la logique de présentation.

Déplacer le modèle de note

Déplacez la Note classe vers le projet WinUINotes.Bus . Il reste une classe de modèle simple avec une logique pour la représentation des données et la gestion de l’état, mais sans aucune fonctionnalité du kit de ressources MVVM. Les ViewModels gèrent les propriétés observables et la notification de modification, et non le modèle lui-même.

  1. Dans le projet WinUINotes.Bus , créez un dossier nommé Models.

  2. Déplacez le Note.cs fichier du projet WinUINotes vers le dossier WinUINotes.Bus/Models .

  3. Mettez à jour l’espace de noms pour qu’il corresponde au nouvel emplacement :

    namespace WinUINotes.Models
    {
        public class Note
        {
            // Existing code remains unchanged
            ...
        }
    }
    

La Note classe est un modèle de données simple. Il n’a pas besoin de notification de modification, car les ViewModels gèrent les propriétés observables et informent l’interface utilisateur des modifications.

Déplacer le modèle AllNotes

Déplacez la AllNotes classe vers le projet WinUINotes.Bus .

  1. Déplacez le AllNotes.cs fichier du projet WinUINotes vers le dossier WinUINotes.Bus/Models .

  2. Mettez à jour l’espace de noms pour qu’il corresponde au nouvel emplacement :

    namespace WinUINotes.Models
    {
        public class AllNotes
        {
            // Existing code remains unchanged
            ...
        }
    }
    

Comme la Note classe, AllNotes est une classe de modèle simple. ViewModel gère le comportement observable et gère la collection de notes.

Créer le AllNotesViewModel

  1. Dans le projet WinUINotes.Bus , créez un dossier nommé ViewModels.

  2. Ajoutez un nouveau fichier de classe nommé AllNotesViewModel.cs avec le contenu suivant :

    using CommunityToolkit.Mvvm.ComponentModel;
    using CommunityToolkit.Mvvm.Input;
    using System.Collections.ObjectModel;
    using System.Threading.Tasks;
    using WinUINotes.Models;
    
    namespace WinUINotes.ViewModels
    {
        public partial class AllNotesViewModel : ObservableObject
        {
            private readonly AllNotes allNotes;
    
            [ObservableProperty]
            private ObservableCollection<Note> notes;
    
            public AllNotesViewModel()
            {
                allNotes = new AllNotes();
                notes = new ObservableCollection<Note>();
            }
    
            [RelayCommand]
            public async Task LoadAsync()
            {
                await allNotes.LoadNotes();
                Notes.Clear();
                foreach (var note in allNotes.Notes)
                {
                    Notes.Add(note);
                }
            }
        }
    }
    

AllNotesViewModel gère la collection de notes affichée dans l’interface utilisateur.

  • [ObservableProperty]: le notes champ génère automatiquement une propriété publique Notes avec notification de modification. Lorsque la Notes collection change, l’interface utilisateur est automatiquement mise à jour.
  • allNotes modèle : ce champ privé contient une instance du AllNotes modèle, qui gère les opérations de données réelles.
  • [RelayCommand]: cet attribut génère une LoadCommand propriété à partir de la LoadAsync() méthode, ce qui permet à l’interface utilisateur de déclencher l’opération de chargement via la liaison de données.
  • LoadAsync() méthode : cette méthode charge les notes du modèle, efface la collection observable actuelle et la remplit avec les notes chargées. Ce modèle garantit que la collection liée à l’interface utilisateur reste synchronisée avec les données sous-jacentes.

La séparation entre le allNotes modèle (opérations de données) et la Notes collection observable (liaison d’interface utilisateur) est un modèle MVVM clé qui conserve les préoccupations séparées et la vue synchronisée avec les données de ViewModel.

En savoir plus dans la documentation :

Créer le NoteViewModel

  1. Dans le dossier ViewModels , ajoutez un nouveau fichier de classe nommé NoteViewModel.cs:

    using CommunityToolkit.Mvvm.ComponentModel;
    using CommunityToolkit.Mvvm.Input;
    using System;
    using System.Threading.Tasks;
    using WinUINotes.Models;
    
    namespace WinUINotes.ViewModels
    {
        public partial class NoteViewModel : ObservableObject
        {
            private Note note;
    
            [ObservableProperty]
            [NotifyCanExecuteChangedFor(nameof(SaveCommand))]
            [NotifyCanExecuteChangedFor(nameof(DeleteCommand))]
            private string filename = string.Empty;
    
            [ObservableProperty]
            [NotifyCanExecuteChangedFor(nameof(SaveCommand))]
            private string text = string.Empty;
    
            [ObservableProperty]
            private DateTime date = DateTime.Now;
    
            public NoteViewModel()
            {
                this.note = new Note();
                this.Filename = note.Filename;
            }
    
            public void InitializeForExistingNote(Note note)
            {
                this.note = note;
                this.Filename = note.Filename;
                this.Text = note.Text;
                this.Date = note.Date;
            }
    
            [RelayCommand(CanExecute = nameof(CanSave))]
            private async Task Save()
            {
                note.Filename = this.Filename;
                note.Text = this.Text;
                note.Date = this.Date;
                await note.SaveAsync();
    
                // Check if the DeleteCommand can now execute
                // (it can if the file now exists)
                DeleteCommand.NotifyCanExecuteChanged();
            }
    
            private bool CanSave()
            {
                return note is not null
                    && !string.IsNullOrWhiteSpace(this.Text)
                    && !string.IsNullOrWhiteSpace(this.Filename);
            }
    
            [RelayCommand(CanExecute = nameof(CanDelete))]
            private async Task Delete()
            {
                await note.DeleteAsync();
                note = new Note();
            }
    
            private bool CanDelete()
            {
                // Note: This is to illustrate how commands can be
                // enabled or disabled.
                // In a real application, you shouldn't perform
                // file operations in your CanExecute logic.
                return note is not null
                    && !string.IsNullOrWhiteSpace(this.Filename)
                    && this.note.NoteFileExists();
            }
        }
    }
    

Le kit NoteViewModel illustre plusieurs fonctionnalités clés du MVVM :

  • [ObservableProperty]: Les champs filename, text, et date génèrent automatiquement des propriétés publiques (Filename, Text, Date) avec prise en charge des notifications de changements.
  • [NotifyCanExecuteChangedFor]: cet attribut garantit que lorsque Filename ou Text change, les commandes associées réévaluent s’ils peuvent s’exécuter. Par exemple, lorsque vous tapez du texte, le bouton Enregistrer active ou désactive automatiquement en fonction de la logique de validation.
  • [RelayCommand(CanExecute = nameof(CanSave))]: Cet attribut génère une SaveCommand propriété liée à la méthode CanSave()de validation. La commande est activée uniquement lorsque les deux Text et Filename ont des valeurs.
  • InitializeForExistingNote(): cette méthode charge les données d’une note existante dans les propriétés ViewModel, qui mettent ensuite à jour l’interface utilisateur via la liaison de données.
  • Logique d’enregistrement : la Save() méthode met à jour le modèle sous-jacent Note avec les valeurs de propriété actuelles et appelle SaveAsync() sur le modèle. Après l’enregistrement, il informe le DeleteCommand qu’il doit réévaluer (dans la mesure où un fichier existe maintenant et peut être supprimé).
  • Logique de suppression : la Delete() méthode appelle DeleteAsync() le modèle de note et crée une note vide.

Plus loin dans ce tutoriel, vous intégrez le service de fichiers pour gérer les opérations de fichier réelles et utilisez la classe du MVVM Toolkit pour notifier d'autres parties de l'application lorsqu'une note est supprimée tout en maintenant un couplage lâche.

En savoir plus dans la documentation :

Mettre à jour les vues pour utiliser les ViewModels

Vous devez maintenant mettre à jour vos pages XAML pour établir une liaison avec les nouveaux ViewModels.

Mettre à jour la vue AllNotesPage

  1. Dans AllNotesPage.xaml, mettez à jour la liaison ItemsSource de ItemsView pour utiliser la propriété Notes du ViewModel.

    <ItemsView ItemsSource="{x:Bind viewModel.Notes}"
    ...
    
  2. Mettez à jour le fichier pour qu’il AllNotesPage.xaml.cs ressemble à ceci :

    using Microsoft.UI.Xaml;
    using Microsoft.UI.Xaml.Controls;
    using Microsoft.UI.Xaml.Navigation;
    using WinUINotes.ViewModels;
    
    namespace WinUINotes.Views
    {
        public sealed partial class AllNotesPage : Page
        {
            private AllNotesViewModel? viewModel;
    
            public AllNotesPage()
            {
                this.InitializeComponent();
                viewModel = new AllNotesViewModel();
            }
    
            private void NewNoteButton_Click(object sender, RoutedEventArgs e)
            {
                Frame.Navigate(typeof(NotePage));
            }
    
            private void ItemsView_ItemInvoked(ItemsView sender, ItemsViewItemInvokedEventArgs args)
            {
                Frame.Navigate(typeof(NotePage), args.InvokedItem);
            }
    
            protected override async void OnNavigatedTo(NavigationEventArgs e)
            {
                base.OnNavigatedTo(e);
    
                if (viewModel is not null)
                {
                    await viewModel.LoadAsync();
                }
            }
        }
    }
    

Dans ce fichier code-behind, le constructeur instancie directement le AllNotesViewModel. La méthode OnNavigatedTo() appelle la méthode LoadAsync() sur le ViewModel lorsque la page est consultée. Cette méthode charge les notes du stockage et met à jour la collection observable. Ce modèle garantit que les données sont toujours actualisées lorsque l’utilisateur accède à la page de toutes les notes.

Plus loin dans ce tutoriel, vous refactorisez ce code pour utiliser l’injection de dépendances, ce qui permet à ViewModel d’être injecté dans le constructeur de page au lieu d’être créé directement. Cette approche améliore la testabilité et facilite la gestion des cycles de vie ViewModel.

Mettre à jour la vue NotePage

  1. Dans NotePage.xaml, mettez à jour les liaisons de données TextBox pour Text et Header afin d'utiliser les propriétés du ViewModel. Mettez à jour les boutons StackPanel pour les lier aux commandes au lieu d’utiliser les événements Click :

    ...
    <TextBox x:Name="NoteEditor"
             Text="{x:Bind noteVm.Text, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
             AcceptsReturn="True"
             TextWrapping="Wrap"
             PlaceholderText="Enter your note"
             Header="{x:Bind noteVm.Date.ToString()}"
             ScrollViewer.VerticalScrollBarVisibility="Auto"
             MaxWidth="400"
             Grid.Column="1"/>
    
    <StackPanel Orientation="Horizontal"
                HorizontalAlignment="Right"
                Spacing="4"
                Grid.Row="1" Grid.Column="1">
        <Button Content="Save" Command="{x:Bind noteVm.SaveCommand}"/>
        <Button Content="Delete" Command="{x:Bind noteVm.DeleteCommand}"/>
    </StackPanel>
    ...
    

    Vous avez également défini UpdateSourceTrigger sur la TextBox.Text liaison pour vous assurer que les modifications sont envoyées au ViewModel au fur et à mesure que l'utilisateur tape. Ce paramètre permet au Save bouton d’activer ou de désactiver en temps réel en fonction de l’entrée.

  2. Dans NotePage.xaml.cs, mettez à jour le code pour utiliser le NoteViewModel.

    using Microsoft.UI.Xaml.Controls;
    using Microsoft.UI.Xaml.Navigation;
    using WinUINotes.Models;
    using WinUINotes.ViewModels;
    
    namespace WinUINotes.Views
    {
        public sealed partial class NotePage : Page
        {
            private NoteViewModel? noteVm;
    
            public NotePage()
            {
                this.InitializeComponent();
            }
    
            protected override void OnNavigatedTo(NavigationEventArgs e)
            {
                base.OnNavigatedTo(e);
                noteVm = new NoteViewModel();
    
                if (e.Parameter is Note note && noteVm is not null)
                {
                    noteVm.InitializeForExistingNote(note);
                }
            }
        }
    }
    

    Les Click événements pour Save et Delete sont supprimés, car les boutons se lient désormais directement aux commandes dans ViewModel. NoteViewModel est instancié dans la méthode OnNavigatedTo(). Si un Note paramètre est passé, il initialise le ViewModel avec les données de note existantes.

En savoir plus dans la documentation :