살짝 고민이 된다. 지난번에 확인하지 못했던 내용을 마저 확인하고 이해한 후에 진도를 나갈지, 우선 전체를 훑어보고 다시 돌아와서 이전에 넘겼던 내용을 제대로 볼 것인지...
앞에서 이해하지 못한 내용이 뒤에서 발목을 잡을 가능성도 있기에 마냥 무시하기도 어렵다.
그러니, 진도를 나가기 전에 가볍게라도 살펴보고 넘어가는걸로 하자.
Host를 생성할 때 서비스를 등록하는 부분에서 services.AddHostedService<MyHostService>()
같은 코드를 보았다. 이 코드를 이해하기 위해 찾아보면 의존성 주입
이라는 말이 나온다. 이게 말은 어려워보이지만 별거 없다.
라이브러리가 참조하는(의존하는) 객체를 런타임에 라이브러리 밖에서 만들어 넘겨주겠다는(주입하는) 것이다. 그것이 가능한 이유는 라이브러리는 객체가 아닌 인터페이스를 참조해서 구현하면 되기 때문이다. 나중에 더 자세히 살펴볼 것이니, 이 정도만 이해하고 넘어가자.
App.xaml
은 아래와 같이 정의되어 있다.
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ui:ThemesDictionary Theme="Light" />
<ui:ControlsDictionary />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
Application.Resources
Application이 사용할 리소스를 정의한다. 아이콘 이미지, 컨트롤의 색상, 모양 같은 것들이 리소스로 정의될 수 있다.ResourceDictionary
런타임에 접근하는 동적 리소스를 정의한다. ResourceDictionary.MergedDictionaries
외부에 정의한 ResourceDictionary를 불러와 병합한다.ui:ThemesDictionary
패키지 WPF-UI
에서 정의한 Light/Dark 테마용 ResourceDictionary를 병합한다.ui:ControlsDictionary
패키지 WPF-UI
에서 정의한 UI-Control용 ResourceDictionary를 불러와 병합한다.Application.Resources
에 정의된 ResourceDictionary는 모든 화면에서 공통으로 참조할 수 있다.이 프로젝트는 WPF-UI
Control을 사용할 것이므로 'WPF UI Gallery' 프로그램을 실행해서 실제 화면에 어떻게 보여지는지 미리 확인하고, 문서(https://wpfui.lepo.co)를 참조해 코딩하는 것이 좋다.
FluentWindow
를 사용한다.RootNavigation
이다.RootContentDialog
이다.여기서 Binding이 어떻게 동작하는지 궁금해질 수 있는데, 일단은 ModelView에서 제공하는 데이터를 컨트롤에 표시해준다는 정도로만 이해하고 넘어가자.
MainWindow는 WPF-UI
의 FluentWindow이고 INavigationWindow 인터페이스를 구현한다. INavigationWindow 인터페이스는 WPF-UI
MVVM 모델과 MainWindow의 NavigationView를 연결한다.
MainWindow의 생성자는 MainWindowViewModel, IPageService, INavigationService
를 인자로 받는다.
WPF-UI
패키지 안에서 이루어지는것 같다.navigationService.SetNavigationControl(RootNavigation)
RootNavigation.SetPageService(pageService)
NavigationView에 PageService를 지정한다. 이렇게하면 NavigationView가 표시할 Page Content를 PageService를 통해 접근할 수 있을 것 같다.MainWindow는 INavigationWindow를 구현한다.
GetNavigation()
MainWindow의 NavigationView를 참조한다.Navigate(Type pageType)
MainWindow의 NavigationView를 통해서 Page를 이동한다.ShowWindow()
MainWindow를 보이게 한다.CloseWindow()
MainWindow를 닫는다.INavigationWindow가 어떻게 사용되는지는 이전에 살펴보았던 ApplicationHostService
의 아래 코드를 참조해볼 수 있다.
private async Task HandleActivationAsync()
{
...
_navigationWindow = (
_serviceProvider.GetService(typeof(INavigationWindow)) as INavigationWindow
)!;
_navigationWindow!.ShowWindow();
_navigationWindow.Navigate(typeof(Views.Pages.DashboardPage));
...
}
_serviceProvider
는 위에 의존성 주입에 대해 설명할 때 언급되었던 ServiceCollection이다. AddSingleton()
으로 추가했던 서비스와 Window, ViewModel에서 INavigationWindow
인스턴스를 찾아 _navigationWindow
에 담는다._navigationWindow
가 가리키는 Window가 MainWindow이고, INavigationWindow를 통해서 MainWindow의 ShowWindow()와 Navigate()를 호출하고 있다.MainWindowViewModel은 다음과 같은 속성을 제공한다.
ViewModel은 ObservableObject를 상속받는다. ViewModel에서 PropertyChanged 이벤트와 Command를 쉽게 구현하기 위한 것인데, 나중에 좀 더 알아보기로 하고 넘어가자.
ViewModel이 ObservableObject를 상속받으면 위 속성은 [ObservableProperty]
Annotation을 통해 Property와 Notification을 쉽게 구현할 수 있다.(컴파일하면 관련 코드가 자동으로 생성된다.)
public partial class MainWindowViewModel : ObservableObject
{
[ObservableProperty]
private string _applicationTitle = "WPF UI - UiDesktopApp1";
...
}