DI(종속성 주입)를 사용하면 ViewModels 및 서비스의 수명 주기를 관리할 수 있습니다. 이렇게 하면 코드를 테스트하기 쉽고 쉽게 유지 관리할 수 있습니다. 이 단계에서는 앱에서 DI를 구성하고 파일 작업에 파일 서비스를 사용하도록 모델을 업데이트합니다.
.NET 종속성 주입 프레임워크에 대한 자세한 배경 정보는 .NET 종속성 주입 및 .NET 자습서 의 종속성 주입 사용을 참조하세요.
Microsoft.Extensions 패키지 설치
프로젝트에 DI 지원을 추가합니다.
Microsoft.Extensions.DependencyInjection및 WinUINotes.Bus 프로젝트 모두에 설치합니다.dotnet add WinUINotes package Microsoft.Extensions.DependencyInjection dotnet add WinUINotes.Bus package Microsoft.Extensions.DependencyInjection
파일 서비스 인터페이스 및 구현 만들기
WinUINotes.Bus 프로젝트에서 Services라는 새 폴더를 만듭니다.
인터페이스 파일
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(); } }파일 서비스 인터페이스는 파일 작업에 대한 메서드를 정의합니다. ViewModels 및 모델에서 파일 처리의 세부 정보를 추상화합니다. 매개 변수 및 반환 값은 모두 기본 .NET 형식 또는 인터페이스입니다. 이 설계를 통해 단위 테스트에서 서비스를 쉽게 조롱하거나 대체할 수 있으므로 느슨한 결합 및 테스트 용이성을 촉진할 수 있습니다.
구현 파일을
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); } } }
이 구현은 WindowsFileService WinRT(Windows 런타임) 및 .NET 스토리지 API를 사용하여 구체적인 파일 작업을 제공합니다.
-
생성자 삽입: 서비스는 생성자에서
IStorageFolder를 수용합니다. 이 방법을 사용하면 서비스를 인스턴스화할 때 스토리지 위치를 구성할 수 있습니다. 이 방법을 사용하면 서비스를 유연하고 테스트할 수 있습니다. -
CreateOrUpdateFileAsync(): 이 메서드는 파일이 이미 있는지 확인하는 데 사용합니다TryGetItemAsync(). 이 경우 메서드는 기존 파일을 업데이트합니다. 그렇지 않으면CreateFileAsync()을(를) 사용하여 새 파일을 만듭니다. 이 방법은 단일 메서드에서 만들기 및 업데이트 시나리오를 모두 처리합니다. -
DeleteFileAsync(): 파일을 삭제하기 전에 이 메서드는 .를 사용하여TryGetItemAsync()파일이 있는지 확인합니다. 존재하지 않는 파일을 삭제하려고 할 때 예외가 발생하는 것을 이 검사가 방지합니다. -
FileExists(): 이 동기 메서드는TryGetItemAsync()비동기 메서드를 호출하여 파일 존재 여부를 확인하고.Result로 차단합니다. 이 방법은 일반적으로 권장되지 않지만 여기서는 동기적이어야 하는 ViewModel의 유효성 검사 메서드를 지원하는CanDelete()데 사용됩니다. -
스토리지 항목 메서드: 및
GetStorageItemsAsync()메서드는GetTextFromFileAsync()WinRT 스토리지 API를 사용하여 파일 및 해당 콘텐츠에 대한 액세스를 제공합니다. 이러한 메서드를 사용하면 모델에서 노트를 로드하고 열거할 수 있습니다.
인터페이스를 IFileService 구현하여 이 클래스를 테스트용 모의 구현 또는 필요한 경우 다른 스토리지 공급자로 쉽게 바꿀 수 있습니다.
다음 문서에서 자세히 알아보세요.
App.xaml.cs에서 종속성 주입을 구성합니다.
파일 서비스를 사용하도록 모델 및 ViewModels를 업데이트하기 전에 서비스를 확인하고 생성자에 삽입할 수 있도록 종속성 주입을 구성합니다.
파일을 업데이트하여 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;
}
이 구성은 필요한 모든 서비스를 사용하여 종속성 주입 컨테이너를 설정합니다.
-
ConfigureServices()메서드: 서비스 컬렉션을 만들고 구성하는 정적 메서드입니다. 이 메서드를 분리하면 구성을 더 쉽게 유지 관리하고 테스트할 수 있습니다. -
Services속성:IServiceProvider을 보유하는 인스턴스 속성입니다. 생성자는 호출ConfigureServices()하여 이 속성을 설정합니다. -
App.Currentstatic 속성: 모델 또는 다른 클래스가 서비스 공급자에 액세스해야 하는 경우에 유용한 현재App인스턴스에 대한 편리한 액세스를 제공합니다. -
IFileService등록:ActivatorUtilities.CreateInstanceWindowsFileService을(를) 사용하여ApplicationData.Current.LocalFolder을(를) 매개 변수로 인스턴스를 생성합니다. 이 방법을 사용하면 등록 시 생성자 매개 변수를 삽입할 수 있습니다. 파일 작업은 상태 비 상태이며 애플리케이션 간에 단일 인스턴스를 공유할 수 있으므로 서비스를 싱글톤으로 등록합니다. - ViewModels 등록: 두 ViewModels를 일시적으로 등록합니다. 즉, 새 인스턴스가 요청 될 때마다 만들어집니다. 이 방법을 사용하면 각 페이지가 깨끗한 상태로 자체 ViewModel 인스턴스를 가져옵니다.
모델 및 기타 클래스는 필요할 때 등록된 서비스를 검색하기 위해 서비스 공급자 App.Current.Services.GetService() 에 액세스할 수 있습니다.
다음 문서에서 자세히 알아보세요.
파일 서비스를 사용하도록 모델 업데이트
이제 종속성 주입을 통해 파일 서비스를 사용할 수 있으므로 이를 사용하도록 모델 클래스를 업데이트합니다. 모델은 파일 서비스를 수신하고 모든 파일 작업에 사용합니다.
메모 모델 업데이트
Note 파일 서비스를 수락하도록 클래스를 업데이트하고 저장, 삭제 및 파일 존재 작업에 사용합니다.
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);
}
}
이제 모델은 Note 생성자 주입을 통해 파일 서비스를 받습니다.
-
생성자: 매개 변수를
IFileService수락하여 종속성을 명시적이고 필수로 만듭니다. 이 디자인은 테스트 가능성을 높이고 모델이 항상 필요한 파일 서비스에 액세스할 수 있도록 합니다. - 파일 이름 생성: 생성자는 현재 타임스탬프를 사용하여 고유한 파일 이름을 자동으로 생성하여 각 노트에 고유한 파일 이름이 있는지 확인합니다.
-
파일 작업: ,
SaveAsync()및DeleteAsync()메서드는NoteFileExists()모두 삽입된 파일 서비스에 위임되며, 모델은 파일 I/O 세부 정보를 구현하는 대신 작업 조정에 초점을 맞췄습니다.
이 방법은 모델에서 서비스 로케이터 패턴(직접 액세스)을 App.Services 사용할 필요가 없도록 하여 테스트 가능성을 향상시키고 종속성을 명확하게 합니다.
AllNotes 모델 업데이트
AllNotes 파일 서비스를 사용하여 스토리지에서 노트를 로드하도록 클래스를 업데이트합니다.
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);
}
}
}
}
AllNotes 모델은 Note 모델과 마찬가지로 생성자 주입을 통해 파일 서비스를 받습니다. 이 클래스는 WinUINotes.Bus 프로젝트에 있으므로 프로젝트 참조 제약 조건으로 인해 프로젝트에서 액세스할 App.Current.ServicesWinUINotes 수 없습니다.
이 메서드는 LoadNotes() 프라이빗 GetFilesInFolderAsync() 메서드를 호출하여 로컬 스토리지 폴더 및 해당 하위 폴더의 모든 파일을 재귀적으로 열거합니다. 각 스토리지 항목에 대해 다음을 수행합니다.
- 폴더인 경우 메서드는 재귀적으로 자신을 호출하여 폴더의 내용을 처리합니다.
- 파일인 경우 파일 서비스가 삽입된 새
Note인스턴스를 만듭니다. - 메모
Filename가 파일 이름으로 설정됩니다. - 노트의
Text는GetTextFromFileAsync()를 사용하여 파일의 내용을 읽어 채워집니다. - 메모
Date는 파일의 생성 날짜로 설정됩니다. - 메모가 관찰 가능한 컬렉션에
Notes추가됩니다.
이 방법을 사용하면 스토리지에서 로드된 모든 노트가 나중에 저장 및 삭제 작업에 필요한 파일 서비스에 액세스할 수 있습니다.
파일 서비스를 사용하도록 ViewModels 업데이트
이제 모델에서 파일 서비스를 사용하므로 ViewModels를 업데이트해야 합니다. 그러나 모델이 파일 작업을 직접 처리하므로 ViewModels는 주로 모델을 오케스트레이션하고 관찰 가능한 속성을 관리하는 데 중점을 줍니다.
AllNotesViewModel 업데이트
업데이트된 AllNotes 모델과 호환되도록 AllNotesViewModel를 업데이트합니다.
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);
}
}
}
}
2단계 이후 변경된 내용은 무엇인가요?
키 변경은 생성자에 매개 변수를 IFileService 추가하는 것입니다. 2단계에서 ViewModel은 매개 변수가 없는 생성자(AllNotes)로 인스턴스화되었습니다allNotes = new AllNotes(). 이제 AllNotes 모델이 작업을 수행하기 위해 파일 서비스를 필요로 하므로, ViewModel은 생성자 주입을 통해 IFileService를 받아 모델에 전달합니다.
이 변경은 적절한 종속성 흐름을 유지합니다. 파일 서비스는 최상위 수준(ViewModel)에 삽입되고 모델로 전달됩니다. ViewModel은 파일 로드 방법에 대한 구현 세부 정보를 알 필요 없이 로드 프로세스를 조정하고 관찰 가능한 Notes 컬렉션을 모델의 데이터와 동기화된 상태로 유지하는 데 계속 집중합니다.
NoteViewModel 업데이트
NoteViewModel 파일 서비스를 삽입하도록 업데이트하고 MVVM 도구 키트의 메시징 시스템을 사용합니다.
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();
}
}
}
2단계 이후 변경된 내용은 무엇인가요?
몇 가지 중요한 변경 사항은 종속성 주입 및 ViewModel 간 통신을 지원합니다.
파일 서비스 주입: 생성자가 이제
IFileService을(를) 파라미터로 받아 필드에 저장합니다. 이 서비스는 새 인스턴스를Note만들 때 모델에 전달되어 모든 노트가 파일 작업을 수행할 수 있도록 합니다.WeakReferenceMessenger: 이제 메서드는 MVVM Toolkit을
WeakReferenceMessenger.Default.Send()사용하여 메모를 삭제한 후NoteDeletedMessage를 브로드캐스트합니다. 이 방법을 사용하면 ViewModels 간에 느슨한 결합이 가능합니다. 애플리케이션의 다른 부분(예:NotePage)은 직접 참조 없이NoteViewModel도 이 메시지를 수신 대기하고 적절하게 응답할 수 있습니다(예: 새로 고친 노트 목록으로 다시 이동).
약한 WeakReferenceMessenger 참조를 사용하여 메모리 누수를 방지하는 MVVM 도구 키트의 주요 기능입니다. 구성 요소는 가비지 수집을 방지하는 강력한 참조를 만들지 않고 메시지를 구독할 수 있습니다.
다음 문서에서 자세히 알아보세요.
NoteDeletedMessage 클래스 만들기
WeakReferenceMessenger 구성 요소 간에 보낼 메시지 클래스가 필요합니다. 메모 삭제 이벤트를 나타내는 새 클래스를 만듭니다.
WinUINotes.Bus 프로젝트에서 새 클래스 파일을
NoteDeletedMessage.cs추가합니다.using CommunityToolkit.Mvvm.Messaging.Messages; using WinUINotes.Models; namespace WinUINotes { public class NoteDeletedMessage : ValueChangedMessage<Note> { public NoteDeletedMessage(Note note) : base(note) { } } }
이 메시지 클래스는 값 변경 알림을 전달하기 위해 MVVM 도구 키트에서 제공하는 특수한 메시지 유형인 ValueChangedMessage<Note>에서 상속됩니다. 생성자는 a Note 를 수락하고 기본 클래스에 전달하여 속성을 통해 Value 메시지 받는 사람이 사용할 수 있도록 합니다.
NoteViewModel가 이 메시지를 보내면, NoteDeletedMessage를 구독하는 모든 구성 요소가 메시지를 수신하고, Value 속성을 통해 삭제된 메모에 액세스할 수 있습니다.
MVVM 도구 키트에서 메시징이 작동하는 방식:
-
보낸 사람: 메서드는
NoteViewModel.Delete().를 사용하여WeakReferenceMessenger.Default.Send(new NoteDeletedMessage(note))메시지를 보냅니다. -
받는 사람: 페이지(와 같이
NotePage)는 메시지를 수신하기 위해IRecipient<NoteDeletedMessage>를 구현하고, 메신저에 등록하여야 합니다. 메시지가 수신되면 페이지가 모든 노트 목록으로 다시 이동할 수 있습니다. - 느슨한 결합: 발신자는 누구(있는 경우)가 수신하는지 알 필요가 없습니다. 수신자는 보낸 사람에게 직접 참조할 필요가 없습니다. 이 설정은 구성 요소를 독립적이고 테스트 가능하게 유지합니다.
약한 참조 접근법의 뜻은, 구성 요소가 가비지 수집되면, 그 메시지 구독이 자동으로 정리되어 메모리 누수가 발생하지 않는다는 것입니다.
종속성 주입을 사용하도록 페이지 업데이트
DI를 통해 ViewModels를 받도록 페이지 생성자를 업데이트합니다.
업데이트 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();
}
}
}
}
2단계 이후 변경된 내용은 무엇인가요?
이제 앱은 직접 new AllNotesViewModel()를 사용하여 만들어내는 대신, App.Current.Services.GetService<AllNotesViewModel>()를 통해 종속성 주입 컨테이너에서 AllNotesViewModel를 가져옵니다. 이 접근 방식에는 몇 가지 이점이 있습니다.
-
자동 종속성 확인: DI 컨테이너는 생성자에 필요한 종속성을
IFileService자동으로 제공합니다AllNotesViewModel. - 수명 주기 관리: DI 컨테이너는 등록된 방법에 따라 ViewModel의 수명 주기를 관리합니다(이 경우 임시로 새 인스턴스 제공).
- 테스트 용이성: 이 패턴을 사용하면 테스트에서 구현을 더 쉽게 교환하거나 종속성을 모의할 수 있습니다.
- 유지 관리: ViewModel의 종속성이 나중에 변경되는 경우 ViewModel이 만들어지는 모든 위치가 아니라 DI 구성만 업데이트하면 됩니다.
나머지 코드는 동일하게 유지됩니다. 사용자가 이 페이지로 이동할 때 OnNavigatedTo() 메서드는 여전히 LoadAsync()를 호출하여 노트 목록을 새로 고칩니다.
업데이트 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);
}
}
}
}
2단계 이후 변경된 내용은 무엇인가요?
몇 가지 중요한 변경 사항은 종속성 주입 및 메시징 기능을 통합합니다.
-
DI 컨테이너의 ViewModel:
NoteViewModel는 이제App.Current.Services.GetService<NoteViewModel>()메서드를 사용하여OnNavigatedTo()종속성 주입 컨테이너에서 직접 인스턴스화되지 않고 검색됩니다. 이 방법을 사용하면 ViewModel이 필요한IFileService종속성을 자동으로 받습니다. -
메시지 등록: 새
RegisterForDeleteMessages()메서드는WeakReferenceMessenger를 사용하여NoteDeletedMessage를 구독합니다. 메모가NoteViewModel.Delete()메서드에서 삭제되면 이 페이지에서 메시지를 받고 다음을 사용하여Frame.GoBack()을 통해, 모든 노트 목록으로 다시 이동합니다. -
메시징 패턴: 이 패턴은 MVVM 도구 키트의 메시징 시스템에서 사용하도록 설정된 느슨한 결합을 보여 줍니다.
NoteViewModel탐색 또는 페이지 구조에 대해 알 필요가 없습니다. 메모가 삭제될 때 메시지를 보내고 페이지는 탐색 응답을 독립적으로 처리합니다. -
수명 주기 타이밍: ViewModel이 인스턴스화되고 메시지 등록이 수행
OnNavigatedTo()되어 페이지가 활성화될 때 모든 항목이 제대로 초기화됩니다.
이 패턴은 문제를 효과적으로 구분합니다. ViewModel은 비즈니스 논리 및 데이터 작업에 중점을 두고 페이지는 탐색과 같은 UI 관련 문제를 처리합니다.
Windows developer