Sdílet prostřednictvím


Přidat injektování závislostí

Injektáž závislostí (DI) pomáhá spravovat životní cyklus modelů a služeb ViewModels. Díky tomu je váš kód testovatelný a snadněji udržovatelný. V tomto kroku nakonfigurujete DI v aplikaci a aktualizujete modely tak, aby používaly souborovou službu pro operace se soubory.

Další informace o rozhraní injektáže závislostí .NET najdete v tématu Injektáž závislostí .NET a použití injektáže závislostí v kurzu .NET .

Instalace balíčků Microsoft.Extensions

Přidejte podporu DI do svých projektů.

  1. Nainstalujte Microsoft.Extensions.DependencyInjection v obou projektech WinUINotes a WinUINotes.Bus.

    dotnet add WinUINotes package Microsoft.Extensions.DependencyInjection
    dotnet add WinUINotes.Bus package Microsoft.Extensions.DependencyInjection
    

Vytvoření rozhraní a implementace souborové služby

  1. V projektu WinUINotes.Bus vytvořte novou složku s názvem Služby.

  2. Přidejte soubor IFileService.csrozhraní:

    using System.Collections.Generic;
    using System.Threading.Tasks;
    using Windows.Storage;
    
    namespace WinUINotes.Services
    {
        public interface IFileService
        {
            Task<IReadOnlyList<IStorageItem>> GetStorageItemsAsync();
            Task<IReadOnlyList<IStorageItem>> GetStorageItemsAsync(IStorageFolder storageFolder);
            Task<string> GetTextFromFileAsync(IStorageFile file);
            Task CreateOrUpdateFileAsync(string filename, string contents);
            Task DeleteFileAsync(string filename);
            bool FileExists(string filename);
            IStorageFolder GetLocalFolder();
        }
    }
    

    Rozhraní souborové služby definuje metody pro operace se soubory. Abstrahuje podrobnosti zpracování souborů z modelů ViewModels a Models. Parametry a návratové hodnoty jsou buď základní typy .NET, nebo rozhraní. Tento návrh zajišťuje, aby služba byla snadno napodobena nebo nahrazena v jednotkových testech, což podporuje volné spojení a testovatelnost.

  3. Přidejte implementační soubor WindowsFileService.cs:

    using System;
    using System.Collections.Generic;
    using System.Threading.Tasks;
    using Windows.Storage;
    
    namespace WinUINotes.Services
    {
        public class WindowsFileService : IFileService
        {
             public StorageFolder storageFolder;
    
             public WindowsFileService(IStorageFolder storageFolder)
             {
                 this.storageFolder = (StorageFolder)storageFolder;
    
                 if (this.storageFolder is null)
                 {
                     throw new ArgumentException("storageFolder must be of type StorageFolder", nameof(storageFolder));
                 }
             }
    
             public async Task CreateOrUpdateFileAsync(string filename, string contents)
             {
                 // Save the note to a file.
                 StorageFile storageFile = (StorageFile)await storageFolder.TryGetItemAsync(filename);
                 if (storageFile is null)
                 {
                     storageFile = await storageFolder.CreateFileAsync(filename, CreationCollisionOption.ReplaceExisting);
                 }
                 await FileIO.WriteTextAsync(storageFile, contents);
             }
    
         public async Task DeleteFileAsync(string filename)
         {
             // Delete the note from the file system.
             StorageFile storageFile = (StorageFile)await storageFolder.TryGetItemAsync(filename);
             if (storageFile is not null)
             {
                 await storageFile.DeleteAsync();
             }
         }
    
         public bool FileExists(string filename)
         {
             StorageFile storageFile = (StorageFile)storageFolder.TryGetItemAsync(filename).AsTask().Result;
             return storageFile is not null;
         }
    
         public IStorageFolder GetLocalFolder()
         {
             return storageFolder;
         }
    
         public async Task<IReadOnlyList<IStorageItem>> GetStorageItemsAsync()
         {
             return await storageFolder.GetItemsAsync();
         }
    
         public async Task<IReadOnlyList<IStorageItem>> GetStorageItemsAsync(IStorageFolder folder)
         {
             return await folder.GetItemsAsync();
         }
    
         public async Task<string> GetTextFromFileAsync(IStorageFile file)
         {
             return await FileIO.ReadTextAsync(file);
         }
        }
    }
    

Implementace WindowsFileService poskytuje konkrétní operace se soubory pomocí prostředí Windows Runtime (WinRT) a rozhraní API úložiště .NET:

  • Injektování konstruktoru: Služba přijímá ve svém konstruktoru IStorageFolder. Tento přístup umožňuje nakonfigurovat umístění úložiště při vytváření instance služby. Díky tomuto přístupu je služba flexibilní a testovatelná.
  • CreateOrUpdateFileAsync(): Tato metoda používá TryGetItemAsync() ke kontrole, jestli soubor již existuje. Pokud ano, metoda aktualizuje existující soubor. V opačném případě vytvoří nový soubor pomocí CreateFileAsync(). Tento přístup zpracovává scénáře vytváření i aktualizace v jedné metodě.
  • DeleteFileAsync(): Před odstraněním souboru tato metoda ověří, zda soubor existuje pomocí TryGetItemAsync(). Tato kontrola zabraňuje vyvolání výjimek při pokusu o odstranění neexistujících souborů.
  • FileExists(): Tato synchronní metoda kontroluje existenci souboru tím, že volá asynchronní metodu TryGetItemAsync() a blokuje pomocí .Result. I když se tento přístup obecně nedoporučuje, používá se zde k podpoře CanDelete() metody ověřování v modelu ViewModel, která musí být synchronní.
  • Metody položek úložiště: Metody GetStorageItemsAsync() a GetTextFromFileAsync() metody poskytují přístup k souborům a jejich obsahu pomocí rozhraní API úložiště WinRT. Tyto metody umožňují modelům načíst a vytvořit výčet poznámek.

Implementací IFileService rozhraní můžete tuto třídu snadno nahradit napodobením implementace pro testování nebo jiného poskytovatele úložiště v případě potřeby.

Další informace najdete v dokumentaci:

Konfigurace závislostní injekce v App.xaml.cs

Před aktualizací modelů a modelů ViewModel pro použití souborové služby nakonfigurujte injektáž závislostí, aby služba byla vyřešena a vložena do konstruktorů.

App.xaml.cs Aktualizujte soubor tak, aby nastavil kontejner DI:

using System;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.UI.Xaml;
using WinUINotes.ViewModels;

namespace WinUINotes;

public partial class App : Application
{
    private readonly IServiceProvider _serviceProvider;

    public App()
    {
        Services = ConfigureServices();
        this.InitializeComponent();
    }

    private static IServiceProvider ConfigureServices()
    {
        var services = new ServiceCollection();

        // Services
        services.AddSingleton<Services.IFileService>(x =>
            ActivatorUtilities.CreateInstance<Services.WindowsFileService>(x,
                            Windows.Storage.ApplicationData.Current.LocalFolder)
        );

        // ViewModels
        services.AddTransient<AllNotesViewModel>();
        services.AddTransient<NoteViewModel>();

        return services.BuildServiceProvider();
    }

    protected override void OnLaunched(LaunchActivatedEventArgs args)
    {
        m_window = new MainWindow();
        m_window.Activate();
    }

    public IServiceProvider Services { get; }

    private Window? m_window;

    public new static App Current => (App)Application.Current;
}

Tato konfigurace nastaví kontejner injektáže závislostí se všemi požadovanými službami:

  • ConfigureServices() metoda: Statická metoda, která vytvoří a nakonfiguruje kolekci služeb. Oddělením této metody lze konfiguraci lépe udržovat a snadněji testovat.
  • Services vlastnost: Vlastnost instance, která obsahuje vlastnost IServiceProvider. Konstruktor nastaví tuto vlastnost voláním ConfigureServices().
  • App.Current statická vlastnost: Poskytuje pohodlný přístup k aktuální App instanci, což je užitečné, když modely nebo jiné třídy potřebují přístup k poskytovateli služeb.
  • IFileService registrace: Používá ActivatorUtilities.CreateInstance se k vytvoření WindowsFileService instance s ApplicationData.Current.LocalFolder parametrem. Tento přístup umožňuje injektáž parametru konstruktoru v době registrace. Zaregistrujte službu jako singleton, protože operace se soubory jsou bezstavové a jedna instance může být sdílena v celé aplikaci.
  • Registrace ViewModels: Zaregistrujte oba ViewModels jako bezestavové, což znamená, že se při každém vyžádání vytvoří nová instance. Tento přístup zajišťuje, že každá stránka získá svou vlastní instanci ViewModel s čistým stavem.

Modely a další třídy mohou mít přístup k poskytovateli služeb prostřednictvím App.Current.Services.GetService() pro načtení registrovaných služeb, kdykoli je to potřeba.

Další informace najdete v dokumentaci:

Aktualizace modelů pro použití souborové služby

Teď, když je souborová služba dostupná prostřednictvím injektáže závislostí, aktualizujte třídy modelu, aby ji používaly. Modely přijímají souborovou službu a používají ji pro všechny operace se soubory.

Aktualizace modelu poznámky

Note Aktualizujte třídu tak, aby přijímala souborovou službu a používala ji k operacím ukládání, odstraňování a existence souborů:

using System;
using System.Threading.Tasks;
using WinUINotes.Services;

namespace WinUINotes.Models;

public class Note
{
    private IFileService fileService;
    public string Filename { get; set; } = string.Empty;
    public string Text { get; set; } = string.Empty;
    public DateTime Date { get; set; } = DateTime.Now;

    public Note(IFileService fileService)
    {
        Filename = "notes" + DateTime.Now.ToBinary().ToString() + ".txt";
        this.fileService = fileService;
    }

    public async Task SaveAsync()
    {
        await fileService.CreateOrUpdateFileAsync(Filename, Text);
    }

    public async Task DeleteAsync()
    {
        await fileService.DeleteFileAsync(Filename);
    }

    public bool NoteFileExists()
    {
        return fileService.FileExists(Filename);
    }
}

Souborová služba je nyní modelu Note předávána prostřednictvím injekce konstruktoru.

  • Konstruktor: Přijímá IFileService parametr, takže závislost je explicitní a povinná. Tento návrh podporuje testovatelnost a zajišťuje, aby model vždy získal přístup ke službě souborů, které potřebuje.
  • Generování názvu souboru: Konstruktor automaticky vygeneruje jedinečný název souboru pomocí aktuálního časového razítka, čímž se zajistí, že každá poznámka má jedinečný název souboru.
  • Operace se soubory: Metody SaveAsync(), DeleteAsync() a NoteFileExists() všechny delegují na vloženou souborovou službu, přičemž model je zaměřen na koordinování operací místo implementaci podrobností souborového vstupu a výstupu.

Tento přístup eliminuje potřebu modelu používat vzor lokátoru služby (přímý přístup k App.Services), což zlepšuje testovatelnost a zpřehledňuje závislosti.

Aktualizace modelu AllNotes

AllNotes Aktualizujte třídu tak, aby načítá poznámky z úložiště pomocí souborové služby:

using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Threading.Tasks;
using Windows.Storage;
using WinUINotes.Services;

namespace WinUINotes.Models;

public class AllNotes
{
        private IFileService fileService;
        public ObservableCollection<Note> Notes { get; set; } = [];

        public AllNotes(IFileService fileService)
        {
            this.fileService = fileService;
        }

        public async Task LoadNotes()
        {
            Notes.Clear();
            await GetFilesInFolderAsync(fileService.GetLocalFolder());
        }

        private async Task GetFilesInFolderAsync(IStorageFolder folder)
        {
            // Each StorageItem can be either a folder or a file.
            IReadOnlyList<IStorageItem> storageItems =
                                        await fileService.GetStorageItemsAsync(folder);
            foreach (IStorageItem item in storageItems)
            {
                if (item.IsOfType(StorageItemTypes.Folder))
                {
                    // Recursively get items from subfolders.
                    await GetFilesInFolderAsync((IStorageFolder)item);
                }
                else if (item.IsOfType(StorageItemTypes.File))
                {
                    IStorageFile file = (IStorageFile)item;
                    Note note = new(fileService)
                    {
                        Filename = file.Name,
                        Text = await fileService.GetTextFromFileAsync(file),
                        Date = file.DateCreated.DateTime
                    };
                    Notes.Add(note);
                }
            }
        }
}

Model AllNotes přijímá souborovou službu prostřednictvím injektáže konstruktoru, stejně jako model Note . Vzhledem k tomu, že tato třída je v WinUINotes.Bus projektu, nemůže získat přístup k App.Current.Services z WinUINotes projektu (kvůli omezením referencí na projekt).

Metoda LoadNotes() volá privátní GetFilesInFolderAsync() metodu pro rekurzivní výčet všech souborů v místní složce úložiště a jejích podsložkách. Pro každou položku úložiště:

  1. Pokud se jedná o složku, metoda rekurzivně volá sama sebe, aby zpracovávala obsah složky.
  2. Pokud se jedná o soubor, vytvoří novou Note instanci s vloženou souborovou službou.
  3. Filename v poznámce je nastaveno na název souboru.
  4. Poznámky Text se vyplní čtením obsahu souboru pomocí GetTextFromFileAsync()
  5. Poznámka Date je nastavená na datum vytvoření souboru.
  6. Poznámka je přidána do Notes pozorovatelné kolekce.

Tento přístup zajišťuje, že všechny poznámky načtené z úložiště mají přístup k souborové službě, kterou potřebují pro budoucí operace ukládání a odstraňování.

Aktualizace modelů ViewModel pro použití souborové služby

U modelů, které teď používají souborovou službu, je potřeba aktualizovat modely ViewModels. Vzhledem k tomu, že modely zpracovávají operace se soubory přímo, se modely ViewModels primárně zaměřují na orchestraci modelů a správu pozorovatelných vlastností.

Aktualizace modelu AllNotesViewModel

AllNotesViewModel Aktualizujte model tak, aby fungoval s aktualizovaným AllNotes modelem:

using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using System.Collections.ObjectModel;
using System.Threading.Tasks;
using WinUINotes.Models;
using WinUINotes.Services;

namespace WinUINotes.ViewModels
{
    public partial class AllNotesViewModel : ObservableObject
    {
        private readonly AllNotes allNotes;

        [ObservableProperty]
        private ObservableCollection<Note> notes;

        public AllNotesViewModel(IFileService fileService)
        {
            allNotes = new AllNotes(fileService);
            notes = new ObservableCollection<Note>();
        }

        [RelayCommand]
        public async Task LoadAsync()
        {
            await allNotes.LoadNotes();
            Notes.Clear();
            foreach (var note in allNotes.Notes)
            {
                Notes.Add(note);
            }
        }
    }
}

Co se od kroku 2 změnilo?

Klíčovou změnou je přidání parametru IFileService do konstruktoru. V kroku 2 ViewModel vytvoří instanci AllNotes s konstruktorem bez parametrů (allNotes = new AllNotes()). Nyní, když model AllNotes vyžaduje, aby souborová služba prováděla své operace, ViewModel přijímá IFileService prostřednictvím injektáže konstruktoru a předává ho modelu.

Tato změna zajišťuje správný tok závislostí – služba pro práci se soubory je injektována na nejvyšší úrovni (ViewModel) a poté plyne směrem k modelu. Model ViewModel se nadále zaměřuje na koordinaci procesu načítání a zachování pozorovatelné Notes kolekce synchronizované s daty modelu, aniž by bylo nutné znát podrobnosti implementace způsobu načítání souborů.

Aktualizace modelu NoteView

NoteViewModel Aktualizujte souborovou službu a použijte systém zasílání zpráv MVVM Toolkit:

using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using CommunityToolkit.Mvvm.Messaging;
using System;
using System.Threading.Tasks;
using WinUINotes.Models;
using WinUINotes.Services;

namespace WinUINotes.ViewModels
{
    public partial class NoteViewModel : ObservableObject
    {
        private Note note;
        private IFileService fileService;

        [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(IFileService fileService)
        {
            this.fileService = fileService;
            this.note = new Note(fileService);
            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(fileService);
            // Send a message from some other module
            WeakReferenceMessenger.Default.Send(new NoteDeletedMessage(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();
        }
    }
}

Co se od kroku 2 změnilo?

Několik důležitých změn podporuje injekci závislostí a komunikaci mezi modely ViewModel.

  1. Injektáž souborové služby: Konstruktor teď přijímá IFileService jako parametr a ukládá ho do pole. Tato služba se předá Note modelu při vytváření nových instancí a zajišťuje, aby všechny instance mohly provádět operace se soubory.

  2. WeakReferenceMessenger: Metoda Delete() nyní používá nástroj MVVM Toolkit WeakReferenceMessenger.Default.Send() k vysílání NoteDeletedMessage po odstranění poznámky. Tento přístup umožňuje volné spojení mezi modely ViewModels – další části aplikace (například NotePage) můžou naslouchat této zprávě a odpovídajícím způsobem reagovat (například přechodem zpět na seznam poznámek, které se aktualizovaly) bez NoteViewModel nutnosti přímého odkazu na ně.

Funkce WeakReferenceMessenger je klíčovou funkcí MVVM Toolkit, která zamezuje vzniku úniků paměti pomocí slabých odkazů. Komponenty se mohou přihlásit k odběru zpráv bez vytváření silných odkazů, které by zabránily garbage collection.

Další informace najdete v dokumentaci:

Vytvoření třídy NoteDeletedMessage

WeakReferenceMessenger potřebuje třídu zprávy k odesílání mezi komponentami. Vytvořte novou třídu, která představuje událost odstranění poznámky:

  1. V projektu WinUINotes.Bus přidejte nový soubor NoteDeletedMessage.cstřídy:

    using CommunityToolkit.Mvvm.Messaging.Messages;
    using WinUINotes.Models;
    
    namespace WinUINotes
    {
        public class NoteDeletedMessage : ValueChangedMessage<Note>
        {
            public NoteDeletedMessage(Note note) : base(note)
            {
            }
        }
    }
    

Tato třída zprávy dědí z ValueChangedMessage<Note>, což je specializovaný typ zprávy poskytované MVVM Toolkit pro přenos oznámení o změnách hodnot. Konstruktor přijímá Note a předá ji do základní třídy, čímž ji zpřístupní příjemcům zprávy prostřednictvím vlastnosti Value. Když NoteViewModel tuto zprávu odešle, každá komponenta přihlášená k NoteDeletedMessage ji obdrží a má přístup k odstraněné poznámce prostřednictvím Value vlastností.

Jak funguje zasílání zpráv v sadě nástrojů MVVM:

  1. Odesílatel: Metoda NoteViewModel.Delete() odešle zprávu pomocí WeakReferenceMessenger.Default.Send(new NoteDeletedMessage(note)).
  2. Přijímač: Stránky (jako NotePage) se mohou zaregistrovat k příjmu zpráv implementací IRecipient<NoteDeletedMessage> a registrací v messengeru. Po přijetí zprávy může stránka přejít zpět do seznamu všech poznámek.
  3. Volné spojení: Odesílatel nemusí vědět, kdo (pokud někdo) naslouchá. Příjemce nepotřebuje přímý odkaz na odesílatele. Toto nastavení udržuje komponenty nezávislé a testovatelné.

Přístup pomocí slabých referencí znamená, že pokud je komponenta odstraněna z paměti, její odběr zpráv se automaticky vyčistí, aniž by to způsobilo úniky paměti.

Aktualizace stránek tak, aby používaly injektáž závislostí

Aktualizujte konstruktory stránky, aby přijímaly třídy ViewModel prostřednictvím DI.

Aktualizace AllNotesPage.xaml.cs

using Microsoft.Extensions.DependencyInjection;
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 = App.Current.Services.GetService<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();
            }
        }
    }
}

Co se od kroku 2 změnilo?

Aplikace teď získá AllNotesViewModel z kontejneru pro injektování závislostí pomocí App.Current.Services.GetService<AllNotesViewModel>() místo přímého vytvoření s new AllNotesViewModel(). Tento přístup má několik výhod:

  1. Automatické řešení závislostí: Kontejner DI automaticky poskytuje IFileService závislost, která AllNotesViewModel vyžaduje v jeho konstruktoru.
  2. Správa životního cyklu: Kontejner DI spravuje životní cyklus modelu ViewModel podle toho, jak byl zaregistrován (v tomto případě přechodným způsobem, který poskytuje čerstvou instanci).
  3. Testovatelnost: Tento model usnadňuje prohození implementací nebo napodobení závislostí v testech.
  4. Udržovatelnost: Pokud se závislosti modelu ViewModel v budoucnu změní, stačí aktualizovat konfiguraci DI, ne na každém místě, kde je model ViewModel vytvořen.

Zbytek kódu zůstane stejný. Metoda OnNavigatedTo() stále volá LoadAsync() , aby aktualizovala seznam poznámek, když uživatel přejde na tuto stránku.

Aktualizace NotePage.xaml.cs

using CommunityToolkit.Mvvm.Messaging;
using Microsoft.Extensions.DependencyInjection;
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();
        }

        public void RegisterForDeleteMessages()
        {
            WeakReferenceMessenger.Default.Register<NoteDeletedMessage>(this, (r, m) =>
            {
                if (Frame.CanGoBack)
                {
                    Frame.GoBack();
                }
            });
        }

        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            base.OnNavigatedTo(e);
            noteVm = App.Current.Services.GetService<NoteViewModel>();
            RegisterForDeleteMessages();

            if (e.Parameter is Note note && noteVm is not null)
            {
                noteVm.InitializeForExistingNote(note);
            }
        }
    }
}

Co se od kroku 2 změnilo?

Několik důležitých změn integruje funkce injektáže závislostí a zasílání zpráv:

  1. ViewModel z kontejneru DI: NoteViewModel je nyní načten z kontejneru pro injektování závislostí pomocí App.Current.Services.GetService<NoteViewModel>() v metodě OnNavigatedTo() namísto jeho přímé tvorby. Tento přístup zajišťuje, že model ViewModel automaticky obdrží požadovanou IFileService závislost.
  2. Registrace zprávy: Nová RegisterForDeleteMessages() metoda se přihlásí k NoteDeletedMessage odběru pomocí metody WeakReferenceMessenger. Když je poznámka odstraněna (z NoteViewModel.Delete() metody), tato stránka obdrží zprávu a přejde zpět do seznamu všech poznámek pomocí Frame.GoBack().
  3. Model zasílání zpráv: Tento model ukazuje volné párování povolené systémem zasílání zpráv MVVM Toolkit. Nemusí NoteViewModel vědět o navigaci nebo struktuře stránky – jednoduše odešle zprávu při odstranění poznámky a stránka zpracovává navigační odpověď nezávisle.
  4. Časování životního cyklu: Objekt ViewModel se vytvoří instance a při registraci zprávy se OnNavigatedTo()zajistí, že se všechno správně inicializuje, když se stránka aktivuje.

Tento model efektivně odděluje obavy: Model ViewModel se zaměřuje na obchodní logiku a operace s daty, zatímco stránka zpracovává problémy specifické pro uživatelské rozhraní, jako je navigace.