Freigeben über


Implementieren von MVVM mit dem MVVM-Toolkit

Nachdem Sie nun die Projektstruktur eingerichtet haben, können Sie mit der Implementierung des MVVM-Musters beginnen, indem Sie das MVVM-Toolkit verwenden. Dieser Schritt umfasst das Erstellen von ViewModels, die die Features des MVVM-Toolkits nutzen, z.B. ObservableObject für Eigenschaftsänderungsbenachrichtigungen und RelayCommand für die Befehlsimplementierung.

Installieren des MVVM Toolkit NuGet-Pakets

Sie müssen das MVVM-Toolkit in den WinUINotes - und WinUINotes.Bus-Projekten installieren.

Verwenden von Visual Studio

  1. Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf das Projekt WinUINotes.Bus .
  2. Wählen Sie "NuGet-Pakete verwalten" aus.
  3. Suchen Sie nach CommunityToolkit.Mvvm , und installieren Sie die neueste stabile Version.
  4. Wiederholen Sie diese Schritte für das WinUINotes-Projekt .

Verwenden von .NET CLI

Alternativ können Sie die .NET CLI verwenden, um das Paket zu installieren:

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

Designentscheidungen für die Model-Schicht

Wenn Sie MVVM implementieren, ist es wichtig zu entscheiden, wie Sie Ihre Modellklassen in Bezug auf die ViewModels strukturieren. In diesem Lernprogramm sind die Modellklassen (Note und AllNotes) für die Datendarstellung, Geschäftslogik und aktualisierung der Datenspeicherung verantwortlich. Die ViewModels behandeln feststellbare Eigenschaften, Änderungsbenachrichtigungen und Befehle für die Ui-Interaktion.

In einer einfacheren Implementierung können Sie einfache alte CLR-Objekte (POCOs) für die Modellklassen ohne Geschäftslogik oder Datenzugriffsmethoden verwenden. In diesem Fall verarbeiten die ViewModels alle Datenvorgänge über die Dienstebene. Für dieses Lernprogramm enthalten die Modellklassen jedoch Methoden zum Laden, Speichern und Löschen von Notizen, um eine klarere Trennung der Verantwortlichkeiten zu ermöglichen und die ViewModels auf die Präsentationslogik zu konzentrieren.

Verschieben des Notizmodells

Verschieben Sie die Note Klasse in das WinUINotes.Bus-Projekt . Es bleibt eine einfache Modellklasse mit einiger Logik für die Datendarstellung und Zustandsverwaltung, aber ohne MVVM-Toolkit-Features. Die ViewModels behandeln die feststellbaren Eigenschaften und die Änderungsbenachrichtigung, nicht das Modell selbst.

  1. Erstellen Sie im Projekt "WinUINotes.Bus " einen neuen Ordner mit dem Namen "Models".

  2. Verschieben Sie die Note.cs Datei aus dem WinUINotes-Projekt in den Ordner "WinUINotes.Bus/Models ".

  3. Aktualisieren Sie den Namespace so, dass er dem neuen Speicherort entspricht:

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

Die Note Klasse ist ein einfaches Datenmodell. Es ist keine Änderungsbenachrichtigung erforderlich, da die ViewModels observable Eigenschaften verwalten und die Benutzeroberfläche über Änderungen benachrichtigen.

Verschieben des AllNotes-Modells

Verschieben Sie die AllNotes Klasse in das WinUINotes.Bus-Projekt .

  1. Verschieben Sie die AllNotes.cs Datei aus dem WinUINotes-Projekt in den Ordner "WinUINotes.Bus/Models ".

  2. Aktualisieren Sie den Namespace so, dass er dem neuen Speicherort entspricht:

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

Wie die Note Klasse ist AllNotes eine einfache Modellklasse. Das ViewModel behandelt das feststellbare Verhalten und verwaltet die Sammlung von Notizen.

Erstellen des AllNotesViewModel

  1. Erstellen Sie im Projekt WinUINotes.Bus einen neuen Ordner mit dem Namen ViewModels.

  2. Fügen Sie eine neue Klassendatei mit dem folgenden Inhalt hinzu AllNotesViewModel.cs :

    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);
                }
            }
        }
    }
    

Die AllNotesViewModel verwaltet die Sammlung von Notizen, die in der Benutzeroberfläche angezeigt werden.

  • [ObservableProperty]: Das notes Feld generiert automatisch eine öffentliche Notes Eigenschaft mit Änderungsbenachrichtigung. Wenn sich die Notes Sammlung ändert, wird die Benutzeroberfläche automatisch aktualisiert.
  • allNotes Modell: Dieses private Feld enthält eine Instanz des AllNotes Modells, die die tatsächlichen Datenvorgänge verarbeitet.
  • [RelayCommand]: Dieses Attribut generiert eine LoadCommand Eigenschaft aus der LoadAsync() Methode, sodass die Benutzeroberfläche den Ladevorgang über die Datenbindung auslösen kann.
  • LoadAsync() methode: Diese Methode lädt Notizen aus dem Modell, löscht die aktuelle observable Auflistung und füllt sie mit den geladenen Notizen auf. Dieses Muster stellt sicher, dass die UI-gebundene Sammlung mit den zugrunde liegenden Daten synchronisiert bleibt.

Die Trennung zwischen dem allNotes Modell (Datenvorgänge) und der Notes observablen Auflistung (UI-Bindung) ist ein wichtiges MVVM-Muster, das die Aspekte voneinander trennt und die Ansicht mit den Daten des ViewModels synchronisiert.

Weitere Informationen finden Sie in den Dokumenten:

Erstellen des NoteViewModel

  1. Fügen Sie im Ordner "ViewModels " eine neue Klassendatei mit dem Namen " hinzu 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();
            }
        }
    }
    

Dieses NoteViewModel zeigt mehrere wichtige MVVM-Toolkit-Funktionen:

  • [ObservableProperty]: Die filenameFelder textdate generieren automatisch öffentliche Eigenschaften (Filename, , TextDate) mit Unterstützung für Änderungsbenachrichtigungen.
  • [NotifyCanExecuteChangedFor]: Dieses Attribut stellt sicher, dass die zugehörigen Befehle, wenn Filename oder Text geändert werden, ob sie ausgeführt werden können, erneut auswerten. Wenn Sie beispielsweise Text eingeben, aktiviert oder deaktiviert die Schaltfläche "Speichern" automatisch basierend auf der Überprüfungslogik.
  • [RelayCommand(CanExecute = nameof(CanSave))]: Dieses Attribut generiert eine SaveCommand Eigenschaft, die an die Überprüfungsmethode CanSave()gebunden ist. Der Befehl ist nur aktiviert, wenn sowohl Text als auch Filename Werte haben.
  • InitializeForExistingNote(): Diese Methode lädt die Daten einer vorhandenen Notiz in die ViewModel-Eigenschaften, die dann die Benutzeroberfläche über die Datenbindung aktualisieren.
  • Speicherlogik: Die Save() Methode aktualisiert das zugrunde liegende Note Modell mit den aktuellen Eigenschaftswerten und Aufrufen SaveAsync() des Modells. Nach dem Speichern wird das DeleteCommand benachrichtigt, dass es erneut überprüft werden sollte (da nun eine Datei vorhanden ist und gelöscht werden kann).
  • Löschlogik: Die Delete() Methode ruft das Notizmodell auf DeleteAsync() und erstellt eine neue leere Notiz.

Später in diesem Lernprogramm integrieren Sie den Dateidienst, um die tatsächlichen Dateivorgänge zu verarbeiten und die Klasse des MVVM-Toolkits WeakReferenceMessenger zu verwenden, um andere Teile der App zu benachrichtigen, wenn eine Notiz gelöscht wird, während sie lose gekoppelt bleiben.

Weitere Informationen finden Sie in den Dokumenten:

Aktualisieren Sie die Ansichten, um die ViewModels zu verwenden

Jetzt müssen Sie Ihre XAML-Seiten aktualisieren, um eine Bindung an die neuen ViewModels zu erstellen.

Aktualisieren der AllNotesPage-Ansicht

  1. In AllNotesPage.xaml aktualisieren Sie die ItemsSource Bindung der ItemsView, um die Notes Eigenschaft des ViewModels zu verwenden.

    <ItemsView ItemsSource="{x:Bind viewModel.Notes}"
    ...
    
  2. Aktualisieren Sie die AllNotesPage.xaml.cs Datei so, dass sie wie folgt aussieht:

    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();
                }
            }
        }
    }
    

In dieser CodeBehind-Datei instanziiert der Konstruktor das AllNotesViewModel direkt. Die OnNavigatedTo() Methode ruft die LoadAsync() Methode für das ViewModel auf, wenn zu der Seite navigiert wird. Diese Methode lädt die Notizen aus dem Speicher und aktualisiert die observable Sammlung. Dieses Muster stellt sicher, dass die Daten immer aktualisiert werden, wenn der Benutzer zur gesamten Notizenseite navigiert.

Später in diesem Lernprogramm umgestalten Sie diesen Code so, dass Abhängigkeitseinfügungen verwendet werden, wodurch das ViewModel in den Seitenkonstruktor eingefügt werden kann, anstatt direkt erstellt zu werden. Dieser Ansatz verbessert die Testbarkeit und erleichtert die Verwaltung von ViewModel-Lebenszyklus.

Aktualisieren der NotePage-Ansicht

  1. Aktualisieren Sie in NotePage.xaml die TextBox-Bindungen für Text und Header, um die Eigenschaften des ViewModel zu verwenden. Aktualisieren Sie die StackPanel Schaltflächen, um eine Bindung an die Befehle herzustellen, anstatt die Click Ereignisse zu verwenden:

    ...
    <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>
    ...
    

    Außerdem legen Sie UpdateSourceTrigger die TextBox.Text Bindung fest, um sicherzustellen, dass Änderungen während der Eingabe durch den Benutzer an das ViewModel gesendet werden. Mit dieser Einstellung kann die Schaltfläche basierend auf der Save Eingabe in Echtzeit aktiviert oder deaktiviert werden.

  2. Aktualisieren Sie in NotePage.xaml.cs den Code, um NoteViewModel zu verwenden.

    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);
                }
            }
        }
    }
    

    Die Click Ereignisse für Save und Delete werden entfernt, da die Schaltflächen jetzt direkt an die Befehle im ViewModel gebunden sind. Das NoteViewModel wird in der OnNavigatedTo()-Methode instanziiert. Wenn ein Note Parameter übergeben wird, initialisiert er das ViewModel mit den vorhandenen Notizdaten.

Weitere Informationen finden Sie in den Dokumenten: