Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
Ahora que tiene la estructura del proyecto en su lugar, puede empezar a implementar el patrón MVVM mediante el kit de herramientas de MVVM. Este paso implica crear ViewModels que aprovechen las características del kit de herramientas de MVVM, como ObservableObject para la notificación de cambio de propiedad y RelayCommand para la implementación de comandos.
Instalación del paquete NuGet de MVVM Toolkit
Debe instalar el kit de herramientas de MVVM en los proyectos WinUINotes y WinUINotes.Bus .
Uso de Visual Studio
- Haga clic con el botón derecho en el proyecto WinUINotes.Bus en el Explorador de soluciones.
- Seleccione Administrar paquetes NuGet.
- Busque CommunityToolkit.Mvvm e instale la versión estable más reciente.
- Repita estos pasos para el proyecto WinUINotes .
Uso de la CLI de .NET
Como alternativa, puede usar la CLI de .NET para instalar el paquete:
dotnet add WinUINotes.Bus package CommunityToolkit.Mvvm
dotnet add WinUINotes package CommunityToolkit.Mvvm
Decisiones de diseño para la capa de modelo
Al implementar MVVM, es importante decidir cómo estructurar las clases de modelo en relación con viewModels. En este tutorial, las clases de modelo (Note y AllNotes) son responsables de la representación de datos, la lógica empresarial y la actualización del almacenamiento de datos. ViewModels controla las propiedades observables, la notificación de cambios y los comandos para la interacción de la interfaz de usuario.
En una implementación más sencilla, podría usar objetos CLR antiguos simples (POCOs) para las clases de modelo, sin incluir lógica de negocio ni métodos de acceso a datos. En ese caso, viewModels controla todas las operaciones de datos a través de la capa de servicio. Sin embargo, para este tutorial, las clases de modelo incluyen métodos para cargar, guardar y eliminar notas para proporcionar una separación más clara de los problemas y mantener los ViewModels centrados en la lógica de presentación.
Mover el modelo de nota
Mueva la Note clase al proyecto WinUINotes.Bus . Sigue siendo una clase de modelo simple con cierta lógica para la representación de datos y la administración de estados, pero sin ninguna característica del kit de herramientas de MVVM. ViewModels controla las propiedades observables y la notificación de cambio, no el propio modelo.
En el proyecto WinUINotes.Bus , cree una carpeta denominada Models.
Mueva el
Note.csarchivo del proyecto WinUINotes a la carpeta WinUINotes.Bus/Models .Actualice el espacio de nombres para que coincida con la nueva ubicación:
namespace WinUINotes.Models { public class Note { // Existing code remains unchanged ... } }
La Note clase es un modelo de datos simple. No necesita notificación de cambios porque ViewModels administra las propiedades observables y notifica a la interfaz de usuario los cambios.
Mover el modelo de AllNotes
Mueva la AllNotes clase al proyecto WinUINotes.Bus .
Mueva el
AllNotes.csarchivo del proyecto WinUINotes a la carpeta WinUINotes.Bus/Models .Actualice el espacio de nombres para que coincida con la nueva ubicación:
namespace WinUINotes.Models { public class AllNotes { // Existing code remains unchanged ... } }
Al igual que la Note clase , AllNotes es una clase de modelo simple. ViewModel controla el comportamiento observable y administra la colección de notas.
Crear el AllNotesViewModel
En el proyecto WinUINotes.Bus , cree una carpeta denominada ViewModels.
Agregue un nuevo archivo de clase denominado
AllNotesViewModel.cscon el siguiente contenido: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 Administra la colección de notas mostradas en la interfaz de usuario:
-
[ObservableProperty]: elnotescampo genera automáticamente una propiedad públicaNotescon notificación de cambio. Cuando cambia laNotescolección, la interfaz de usuario se actualiza automáticamente. -
allNotesmodel: este campo privado contiene una instancia delAllNotesmodelo, que controla las operaciones de datos reales. -
[RelayCommand]: este atributo genera unaLoadCommandpropiedad a partir delLoadAsync()método , lo que permite que la interfaz de usuario desencadene la operación de carga a través del enlace de datos. -
LoadAsync()method: este método carga notas del modelo, borra la colección observable actual y la rellena con las notas cargadas. Este patrón garantiza que la colección enlazada a la interfaz de usuario permanezca sincronizada con los datos subyacentes.
La separación entre el allNotes modelo (operaciones de datos) y la Notes colección observable (enlace de interfaz de usuario) es un patrón de MVVM clave que mantiene las preocupaciones separadas y la vista sincronizada con los datos de ViewModel.
Obtenga más información en los documentos:
Creación de NoteViewModel
En la carpeta ViewModels , agregue un nuevo archivo de clase denominado
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(); } } }
El NoteViewModel demuestra varias características clave de MVVM Toolkit.
-
[ObservableProperty]: losfilenamecampos ,textydategeneran automáticamente propiedades públicas (Filename,Text,Date) con compatibilidad con notificaciones de cambios. -
[NotifyCanExecuteChangedFor]: este atributo garantiza que, cuandoFilenameoTextcambia, los comandos asociados vuelven a evaluar si se pueden ejecutar. Por ejemplo, al escribir texto, el botón Guardar habilita o deshabilita automáticamente en función de la lógica de validación. -
[RelayCommand(CanExecute = nameof(CanSave))]: este atributo genera unaSaveCommandpropiedad enlazada al métodoCanSave()de validación . El comando solo está habilitado cuando ambosTextyFilenametienen valores. -
InitializeForExistingNote(): este método carga los datos de una nota existente en las propiedades ViewModel, que luego actualizan la interfaz de usuario a través del enlace de datos. -
Lógica de guardado:
Save()método actualiza elNotemodelo subyacente con los valores de propiedad actuales y llama aSaveAsync()en el modelo. Después de guardar, notifica aDeleteCommandque debe volver a evaluar (ya que ahora existe un archivo y se puede eliminar). -
Eliminar lógica: el
Delete()método llamaDeleteAsync()al modelo de nota y crea una nueva nota vacía.
Más adelante en este tutorial, integrará el servicio de archivos para controlar las operaciones de archivos reales y usará la clase del WeakReferenceMessenger kit de herramientas de MVVM para notificar a otras partes de la aplicación cuando se elimina una nota mientras permanece acoplado flexiblemente.
Obtenga más información en los documentos:
Actualización de las vistas para usar ViewModels
Ahora debes actualizar las páginas XAML para enlazar a los nuevos ViewModels.
Actualizar la vista de AllNotesPage
En
AllNotesPage.xaml, actualice laItemsSourcevinculación deItemsViewpara que utilice la propiedad del ViewModelNotes.<ItemsView ItemsSource="{x:Bind viewModel.Notes}" ...Actualice el
AllNotesPage.xaml.csarchivo para que tenga este aspecto: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(); } } } }
En este archivo de código subyacente, el constructor instancia directamente el AllNotesViewModel. El OnNavigatedTo() método llama al LoadAsync() método en viewModel cuando se navega a la página. Este método carga las notas del almacenamiento y actualiza la colección observable. Este patrón garantiza que los datos siempre se actualizan cuando el usuario navega a la página de todas las notas.
Más adelante en este tutorial, refactoriza este código para usar la inserción de dependencias, lo que permite insertar ViewModel en el constructor de página en lugar de crearse directamente. Este enfoque mejora la capacidad de prueba y facilita la administración de los ciclos de vida de ViewModel.
Actualizar la vista NotePage
En
NotePage.xaml, actualice lasTextBoxvinculaciones deTextyHeaderpara usar las propiedades del ViewModel. Actualice losStackPanelbotones para enlazar a los comandos en lugar de usar losClickeventos:... <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> ...También se establece
UpdateSourceTriggeren laTextBox.Textvinculación para asegurarse de que los cambios se envían al ViewModel mientras el usuario escribe. Esta configuración permite que elSavebotón habilite o deshabilite en tiempo real en función de la entrada.En
NotePage.xaml.cs, actualice el código para usar :NoteViewModelusing 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); } } } }Los
Clickeventos deSaveyDeletese quitan, ya que los botones ahora se enlazan directamente a los comandos de ViewModel. Se instancia elNoteViewModelen el métodoOnNavigatedTo(). Si se pasa unNoteparámetro, inicializa el ViewModel con los datos de la nota existentes.
Obtenga más información en los documentos: