Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Теперь, когда у вас есть структура проекта, можно начать реализацию шаблона MVVM с помощью набора средств MVVM. Этот шаг включает создание ViewModels, использующих функции набора средств MVVM, такие как ObservableObject уведомление об изменении свойств и RelayCommand реализация команд.
Установите пакет NuGet MVVM Toolkit
Необходимо установить набор средств MVVM в проектах WinUINotes и WinUINotes.Bus .
Использование Visual Studio
- Щелкните правой кнопкой мыши проект WinUINotes.Bus в обозревателе решений.
- Выберите Manage NuGet Packages... (Управление пакетами NuGet...).
- Найдите CommunityToolkit.Mvvm и установите последнюю стабильную версию.
- Повторите эти действия для проекта WinUINotes .
Использование .NET CLI
Кроме того, для установки пакета можно использовать интерфейс командной строки .NET:
dotnet add WinUINotes.Bus package CommunityToolkit.Mvvm
dotnet add WinUINotes package CommunityToolkit.Mvvm
Решения по проектированию для уровня модели
При реализации MVVM важно решить, как структурировать классы моделей в отношении ViewModels. В этом руководстве классы моделей (Note и AllNotes) отвечают за представление данных, бизнес-логику и обновление хранилища данных. ViewModels обрабатывает наблюдаемые свойства, уведомления об изменениях и команды для взаимодействия с пользовательским интерфейсом.
В более простой реализации можно использовать обычные старые объекты CLR (POC) для классов моделей без методов бизнес-логики или доступа к данным. В этом случае ViewModels обрабатывает все операции данных через слой служб. Однако для этого руководства классы моделей включают методы загрузки, сохранения и удаления заметок, чтобы обеспечить более четкое разделение проблем и держать ViewModels сосредоточены на логике презентации.
Перемещение модели заметок
Переместите класс Note в проект WinUINotes.Bus. Он остается простым классом модели с некоторой логикой для управления данными и управления состоянием, но без каких-либо функций набора средств MVVM. ViewModels обрабатывает наблюдаемые свойства и уведомление об изменении, а не саму модель.
В проекте WinUINotes.Bus создайте новую папку с именем Models.
Note.csПереместите файл из проекта WinUINotes в папку WinUINotes.Bus/Models.Обновите пространство имен, чтобы соответствовать новому расположению:
namespace WinUINotes.Models { public class Note { // Existing code remains unchanged ... } }
Класс Note — это простая модель данных. Для этого не требуется уведомление об изменении, так как ViewModels управляет наблюдаемыми свойствами и уведомляет пользовательский интерфейс об изменениях.
Перемещение модели AllNotes
Переместите класс AllNotes в проект WinUINotes.Bus.
AllNotes.csПереместите файл из проекта WinUINotes в папку WinUINotes.Bus/Models.Обновите пространство имен, чтобы соответствовать новому расположению:
namespace WinUINotes.Models { public class AllNotes { // Existing code remains unchanged ... } }
Как и Note класс, AllNotes это простой класс модели. ViewModel обрабатывает наблюдаемое поведение и управляет коллекцией заметок.
Создайте AllNotesViewModel
В проекте WinUINotes.Bus создайте новую папку с именем ViewModels.
Добавьте новый файл
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); } } } }
Управляет AllNotesViewModel коллекцией заметок, отображаемых в пользовательском интерфейсе:
-
[ObservableProperty]notes: поле автоматически создает общедоступноеNotesсвойство с уведомлением об изменении.NotesПри изменении коллекции пользовательский интерфейс автоматически обновляется. -
allNotesмодель. Это частное поле содержит экземплярAllNotesмодели, которая обрабатывает фактические операции с данными. -
[RelayCommand]: этот атрибут создаетLoadCommandсвойство изLoadAsync()метода, позволяя пользовательскому интерфейсу активировать операцию загрузки через привязку данных. -
LoadAsync()метод. Этот метод загружает заметки из модели, очищает текущую наблюдаемую коллекцию и заполняет ее загруженными заметками. Этот шаблон гарантирует, что коллекция, привязанная к пользовательскому интерфейсу, остается синхронизирована с базовыми данными.
Разделение между allNotes моделью (операциями с данными) и Notes наблюдаемой коллекцией (привязкой пользовательского интерфейса) является ключевым шаблоном MVVM, который разделяет обязанности и синхронизирует представление с данными ViewModel.
Дополнительные сведения см. в документации:
Создайте NoteViewModel
В папке ViewModels добавьте новый файл класса с именем
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(); } } }
NoteViewModel демонстрирует несколько ключевых функций MVVM Toolkit:
-
[ObservableProperty]: поляfilename,textиdateавтоматически создают общедоступные свойства (Filename,Text,Date) с поддержкой уведомлений об изменении. -
[NotifyCanExecuteChangedFor]: этот атрибут гарантирует, что приFilenameизменении илиTextизменении связанные команды повторно оценивают, могут ли они выполняться. Например, при вводе текста кнопка "Сохранить" автоматически включает или отключает на основе логики проверки. -
[RelayCommand(CanExecute = nameof(CanSave))]: этот атрибут создаетSaveCommandсвойство, привязанное к методуCanSave()проверки. Эта команда активируется только в том случае, если уTextиFilenameесть значения. -
InitializeForExistingNote(): этот метод загружает существующие данные заметки в свойства ViewModel, которые затем обновляют пользовательский интерфейс с помощью привязки данных. -
Логика сохранения: Метод
Save()обновляет базовуюNoteмодель с текущими значениями свойств и вызываетSaveAsync()модели. После сохранения он уведомляетDeleteCommandо том, что он должен быть повторно оценен (так как файл теперь существует и может быть удален). -
Удаление логики:
Delete()метод вызываетDeleteAsync()модель заметок и создает новую пустую заметку.
Далее в этом руководстве вы интегрируете службу файлов для обработки фактических операций с файлами и используете класс MVVM Toolkit WeakReferenceMessenger , чтобы уведомить другие части приложения, когда заметка удаляется, оставаясь слабо связанной.
Дополнительные сведения см. в документации:
Обновление представлений для использования ViewModels
Теперь необходимо обновить страницы XAML, чтобы привязаться к новым ViewModels.
Обновление представления AllNotesPage
В
AllNotesPage.xamlобновите привязкуItemsSourceдляItemsView, чтобы использовать свойствоNotesиз ViewModel.<ItemsView ItemsSource="{x:Bind viewModel.Notes}" ...Обновите файл
AllNotesPage.xaml.cs, чтобы он выглядел так: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(); } } } }
В этом файле программного кода конструктор создает экземпляр AllNotesViewModel непосредственно. Метод OnNavigatedTo() вызывает LoadAsync() метод в ViewModel при переходе на страницу. Этот метод загружает заметки из хранилища и обновляет наблюдаемую коллекцию. Этот шаблон гарантирует, что данные всегда обновляются при переходе пользователя на страницу всех заметок.
Далее в этом руководстве вы рефакторите этот код для использования внедрения зависимостей, что позволяет внедрить ViewModel в конструктор страницы вместо создания напрямую. Этот подход повышает удобство тестирования и упрощает управление жизненными циклами ViewModel.
Обновить представление NotePage
В
NotePage.xamlобновите привязкиTextBoxдляTextиHeader, чтобы использовать свойства ViewModel. Обновите кнопкиStackPanel, чтобы привязывать их к командам вместо использования событий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> ...Вы также настраиваете
UpdateSourceTriggerпривязкуTextBox.Text, чтобы изменения отправлялись в ViewModel по мере ввода данных пользователем. Этот параметр позволяет кнопкеSaveвключить или отключить в режиме реального времени на основе входных данных.В
NotePage.xaml.cs, обновите код, чтобы использовать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); } } } }События
ClickдляSaveиDeleteудаляются, так как кнопки теперь привязываются непосредственно к командам в ViewModel. ЭкземплярNoteViewModelсоздается в методеOnNavigatedTo(). Если передается параметрNote, он инициализирует ViewModel с уже существующими данными заметки.
Дополнительные сведения см. в документации:
Windows developer