Bagikan melalui


Tambahkan injeksi dependensi

Injeksi dependensi (DI) membantu Anda mengelola siklus hidup ViewModels dan layanan Anda. Ini membuat kode Anda lebih dapat diuji dan lebih mudah dipertahankan. Dalam langkah ini, Anda mengonfigurasi DI di aplikasi dan memperbarui model untuk menggunakan layanan file untuk operasi file.

Untuk latar belakang selengkapnya tentang kerangka kerja injeksi dependensi .NET, lihat injeksi dependensi .NET dan gunakan injeksi dependensi dalam tutorial .NET .

Menginstal paket Microsoft.Extensions

Tambahkan dukungan DI ke proyek Anda.

  1. Instal Microsoft.Extensions.DependencyInjection di proyek WinUINotes dan WinUINotes.Bus :

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

Membuat antarmuka dan implementasi layanan file

  1. Di proyek WinUINotes.Bus , buat folder baru bernama Layanan.

  2. Tambahkan antarmuka file IFileService.cs:

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

    Antarmuka layanan file mendefinisikan metode untuk operasi file. Ini menyederhanakan detail penanganan file dari ViewModel dan Model. Parameter dan nilai yang dikembalikan semuanya adalah jenis atau antarmuka .NET dasar. Desain ini memastikan bahwa layanan dapat dengan mudah ditipu atau diganti dalam pengujian unit, mempromosikan kopling longgar dan kemampuan pengujian.

  3. Tambahkan file WindowsFileService.csimplementasi :

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

Implementasi ini WindowsFileService menyediakan operasi file konkret dengan menggunakan API penyimpanan Windows Runtime (WinRT) dan .NET:

  • Injeksi konstruktor: layanan menerima IStorageFolder di dalam konstruktornya. Pendekatan ini memungkinkan Anda untuk mengonfigurasi lokasi penyimpanan saat Anda membuat instans layanan. Pendekatan ini membuat layanan fleksibel dan dapat diuji.
  • CreateOrUpdateFileAsync(): Metode ini menggunakan TryGetItemAsync() untuk memeriksa apakah file sudah ada. Jika ya, metode memperbarui file yang ada. Jika tidak, ia membuat file baru dengan menggunakan CreateFileAsync(). Pendekatan ini menangani skenario buat dan perbarui dalam satu metode.
  • DeleteFileAsync(): Sebelum menghapus file, metode ini memverifikasi bahwa file ada dengan menggunakan TryGetItemAsync(). Pemeriksaan ini mencegah pengecualian terjadi ketika mencoba menghapus file yang tidak ada.
  • FileExists(): Metode sinkron ini memeriksa keberadaan file dengan memanggil asinkron TryGetItemAsync() dan memblokir dengan .Result. Meskipun pendekatan ini umumnya tidak disarankan, pendekatan ini digunakan di sini untuk mendukung CanDelete() metode validasi di ViewModel, yang harus sinkron.
  • Metode item penyimpanan: Metode GetStorageItemsAsync() dan GetTextFromFileAsync() menyediakan akses ke file dan kontennya dengan menggunakan API penyimpanan WinRT. Metode ini memungkinkan Model memuat dan menghitung catatan.

Dengan menerapkan IFileService antarmuka, Anda dapat dengan mudah mengganti kelas ini dengan implementasi tiruan untuk pengujian atau penyedia penyimpanan yang berbeda jika diperlukan.

Pelajari selengkapnya di dokumen:

Mengonfigurasi injeksi ketergantungan di App.xaml.cs

Sebelum memperbarui model dan ViewModels untuk menggunakan layanan file, konfigurasikan injeksi dependensi sehingga layanan dapat diselesaikan dan disuntikkan ke konstruktor.

Perbarui file App.xaml.cs untuk menyiapkan DI container.

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

Konfigurasi ini menyiapkan kontainer injeksi dependensi dengan semua layanan yang diperlukan:

  • ConfigureServices() metode: Metode statis yang membuat dan mengonfigurasi kumpulan layanan. Memisahkan metode ini membuat konfigurasi lebih dapat dipertahankan dan lebih mudah diuji.
  • Services properti: Properti instans IServiceProvideryang menyimpan . Konstruktor mengatur properti ini dengan memanggil ConfigureServices().
  • App.Current properti statis: Menyediakan akses mudah ke instans saat ini App , yang berguna ketika model atau kelas lain perlu mengakses penyedia layanan.
  • IFileService pendaftaran: Menggunakan ActivatorUtilities.CreateInstance untuk membuat instans WindowsFileService dengan ApplicationData.Current.LocalFolder sebagai parameter. Pendekatan ini memungkinkan parameter konstruktor disuntikkan pada waktu pendaftaran. Daftarkan layanan sebagai singleton karena operasi file tidak menyimpan status dan satu instans dapat dibagikan di seluruh aplikasi.
  • Pendaftaran ViewModels: Daftarkan kedua ViewModels sebagai sementara, yang berarti instans baru dibuat setiap kali diminta. Pendekatan ini memastikan setiap halaman mendapatkan instans ViewModel sendiri dengan status bersih.

Model-model dan kelas lain dapat mengakses penyedia layanan melalui App.Current.Services.GetService() untuk mengambil layanan terdaftar saat diperlukan.

Pelajari selengkapnya di dokumen:

Mengupdate model agar memanfaatkan layanan berkas

Sekarang setelah layanan file tersedia melalui injeksi dependensi, perbarui kelas model untuk menggunakannya. Model menerima layanan berkas dan menggunakannya untuk semua operasi berkas.

Memperbarui model Catatan

Perbarui kelas Note untuk menerima layanan file dan menggunakannya untuk operasi simpan, hapus, dan keberadaan file.

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

Model Note sekarang menerima layanan file melalui injeksi konstruktor:

  • Konstruktor: Menerima IFileService parameter, membuat dependensi eksplisit dan diperlukan. Desain ini mempromosikan keterujian dan memastikan model selalu memiliki akses ke layanan file yang dibutuhkan.
  • Pembuatan nama file: Konstruktor secara otomatis menghasilkan nama file unik dengan menggunakan tanda waktu saat ini, memastikan setiap catatan memiliki nama file yang berbeda.
  • Operasi file: Metode SaveAsync(), , DeleteAsync()dan NoteFileExists() semuanya mendelegasikan ke layanan file yang disuntikkan, menjaga model tetap fokus pada operasi koordinasi daripada menerapkan detail I/O file.

Pendekatan ini menghilangkan kebutuhan model untuk menggunakan pola pencari layanan (mengakses App.Services secara langsung), yang meningkatkan kemampuan pengujian dan membuat dependensi menjadi jelas.

Memperbarui model AllNotes

AllNotes Perbarui kelas untuk memuat catatan dari penyimpanan dengan menggunakan layanan file:

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 menerima layanan file melalui injeksi konstruktor, sama seperti Note model. Karena kelas ini berada dalam WinUINotes.Bus proyek, kelas ini tidak dapat mengakses App.Current.Services dari WinUINotes proyek (karena kendala referensi proyek).

Metode ini LoadNotes() memanggil metode privat GetFilesInFolderAsync() untuk menghitung semua file secara rekursif di folder penyimpanan lokal dan subfoldernya. Untuk setiap item penyimpanan:

  1. Jika ini adalah folder, metode secara rekursif memanggil dirinya sendiri untuk memproses konten folder
  2. Jika ini merupakan file, akan dibuat instans baru Note dengan layanan file yang disuntikkan
  3. Catatan Filename diatur ke nama file
  4. Catatan Text diisi dengan membaca konten file dengan menggunakan GetTextFromFileAsync()
  5. Atribut dari catatan Date diatur ke tanggal pembuatan file
  6. Catatan ditambahkan ke dalam koleksi Notes yang dapat diamati

Pendekatan ini memastikan semua catatan yang dimuat dari penyimpanan memiliki akses ke layanan file yang mereka butuhkan untuk operasi penyimpanan dan penghapusan di masa mendatang.

Perbarui ViewModels untuk menggunakan layanan file

Dengan model yang sekarang menggunakan layanan file, Anda perlu memperbarui ViewModels. Namun, karena model menangani operasi file secara langsung, ViewModels terutama fokus pada mengatur model dan mengelola properti yang dapat diamati.

Memperbarui AllNotesViewModel

Perbarui AllNotesViewModel agar dapat bekerja dengan model AllNotes yang telah diperbarui.

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

Apa yang berubah sejak Langkah 2?

Perubahan kunci adalah penambahan IFileService parameter ke konstruktor. Di Langkah 2, ViewModel dibuat AllNotes dengan konstruktor tanpa parameter (allNotes = new AllNotes()). Sekarang karena model AllNotes memerlukan layanan file untuk melakukan operasinya, ViewModel menerima IFileService melalui injeksi konstruktor dan meneruskannya ke model.

Perubahan ini mempertahankan alur dependensi yang tepat - layanan file disuntikkan di tingkat atas (ViewModel) dan mengalir ke model. ViewModel terus fokus pada koordinasi proses pemuatan dan menjaga koleksi yang dapat Notes diamati tetap sinkron dengan data model, tanpa perlu mengetahui detail implementasi tentang bagaimana file dimuat.

Memperbarui NoteViewModel

Perbarui NoteViewModel untuk menyuntikkan layanan file dan menggunakan sistem perpesanan dari 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();
        }
    }
}

Apa yang berubah sejak Langkah 2?

Beberapa perubahan penting mendukung injeksi dependensi dan komunikasi antar-ViewModel:

  1. Injeksi layanan file: Sekarang konstruktor menerima IFileService sebagai parameter dan menyimpannya di dalam atribut. Layanan ini diteruskan ke model Note saat membuat instans baru, memastikan semua catatan dapat melakukan operasi file.

  2. WeakReferenceMessenger: Metode Delete() ini sekarang menggunakan MVVM Toolkit WeakReferenceMessenger.Default.Send() untuk menyiarkan NoteDeletedMessage setelah menghapus catatan. Pendekatan ini memungkinkan kopling longgar antara ViewModels - bagian lain dari aplikasi (seperti NotePage) dapat mendengarkan pesan ini dan merespons dengan tepat (misalnya, dengan menavigasi kembali ke daftar catatan, yang telah di-refresh) tanpa NoteViewModel memerlukan referensi langsung kepada mereka.

WeakReferenceMessenger adalah fitur utama dari Toolkit MVVM yang mencegah kebocoran memori dengan menggunakan referensi yang lemah. Komponen dapat berlangganan pesan tanpa membuat referensi kuat yang akan mencegah pengumpulan sampah.

Pelajari selengkapnya di dokumen:

Membuat kelas NoteDeletedMessage

Diperlukan WeakReferenceMessenger sebagai kelas pesan untuk mengirim antar komponen. Buat kelas baru untuk mewakili peristiwa penghapusan catatan:

  1. Dalam proyek WinUINotes.Bus , tambahkan file NoteDeletedMessage.cskelas baru :

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

Kelas pesan ini mewarisi dari ValueChangedMessage<Note>, yang merupakan jenis pesan khusus yang disediakan oleh Toolkit MVVM untuk membawa pemberitahuan perubahan nilai. Konstruktor menerima Note dan meneruskannya ke kelas dasar, membuatnya tersedia untuk penerima pesan melalui Value properti. Saat NoteViewModel mengirim pesan ini, komponen apa pun yang berlangganan ke NoteDeletedMessage menerimanya dan dapat mengakses catatan yang dihapus melalui properti Value.

Cara kerja olahpesan di Toolkit MVVM:

  1. Pengirim: Metode NoteViewModel.Delete() mengirim pesan dengan menggunakan WeakReferenceMessenger.Default.Send(new NoteDeletedMessage(note)).
  2. Penerima: Halaman (seperti NotePage) dapat mendaftar untuk menerima pesan dengan menerapkan IRecipient<NoteDeletedMessage> dan mendaftar dengan messenger. Saat pesan diterima, halaman dapat menavigasi kembali ke daftar semua catatan.
  3. Kopling longgar: Pengirim tidak perlu tahu siapa (jika ada) yang mendengarkan. Penerima tidak memerlukan referensi langsung ke pengirim. Penyiapan ini membuat komponen Anda tetap independen dan dapat diuji.

Pendekatan referensi yang lemah berarti bahwa jika komponen adalah sampah yang dikumpulkan, langganan pesannya secara otomatis dibersihkan tanpa menyebabkan kebocoran memori.

Memperbarui halaman untuk menggunakan injeksi dependensi

Perbarui konstruktor halaman Anda untuk menerima ViewModels melalui DI.

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

Apa yang berubah sejak Langkah 2?

Aplikasi ini sekarang mendapatkan AllNotesViewModel dari kontainer injeksi dependensi dengan menggunakan App.Current.Services.GetService<AllNotesViewModel>() alih-alih membuatnya langsung dengan new AllNotesViewModel(). Pendekatan ini memiliki beberapa manfaat:

  1. Resolusi dependensi otomatis: Kontainer DI secara otomatis menyediakan IFileService dependensi yang diperlukan oleh AllNotesViewModel dalam konstruktornya.
  2. Manajemen siklus hidup: Kontainer DI mengelola siklus hidup ViewModel sesuai dengan cara pendaftarannya (sebagai sementara dalam hal ini, menyediakan instans baru).
  3. Kemampuan pengujian: Pola ini memudahkan untuk menukar implementasi atau menipu dependensi dalam pengujian.
  4. Ketahanan: Jika dependensi ViewModel berubah di masa mendatang, Anda hanya perlu memperbarui konfigurasi DI, bukan setiap tempat di mana ViewModel dibuat.

Sisa kode tetap sama. Metode OnNavigatedTo() ini masih memanggil LoadAsync() untuk menyegarkan daftar catatan saat pengguna menavigasi ke halaman ini.

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

Apa yang berubah sejak Langkah 2?

Beberapa perubahan penting mengintegrasikan injeksi dependensi dan fitur olahpesan:

  1. ViewModel dari kontainer DI: Sekarang NoteViewModel diambil dari kontainer injeksi dependensi dengan menggunakan App.Current.Services.GetService<NoteViewModel>() dalam metode OnNavigatedTo() alih-alih dibuat secara langsung. Pendekatan ini memastikan ViewModel secara otomatis menerima dependensi yang diperlukan IFileService .
  2. Pendaftaran pesan: Metode baru RegisterForDeleteMessages() berlangganan NoteDeletedMessage dengan menggunakan WeakReferenceMessenger. Ketika catatan dihapus (dari NoteViewModel.Delete() metode), halaman ini menerima pesan dan menavigasi kembali ke daftar semua catatan dengan menggunakan Frame.GoBack().
  3. Pola olahpesan: Pola ini menunjukkan penghubungan longgar yang diaktifkan oleh sistem olahpesan MVVM Toolkit. NoteViewModel Tidak perlu tahu tentang navigasi atau struktur halaman - itu hanya mengirim pesan ketika catatan dihapus, dan halaman menangani respons navigasi secara independen.
  4. Waktu siklus hidup: ViewModel dibuat dan pendaftaran pesan terjadi di OnNavigatedTo(), memastikan semuanya diinisialisasi dengan benar ketika halaman menjadi aktif.

Pola ini memisahkan masalah secara efektif: ViewModel berfokus pada logika bisnis dan operasi data, sementara halaman menangani masalah khusus UI seperti navigasi.