View와 ViewModel을 어떻게 매핑하시나요?

SW 아키텍처를 전반적으로 설계하는 도중 궁금증이 들어 질문드립니다.

MVVM 구조로 프로그램을 설계하면 View와 ViewModel을 매핑해야합니다.
방법마다 장단점이 있는걸 알지만 다들 어떻게 하시는지 궁금합니다.

  1. DataTemplate 방식
    <DataTemplate DataType="{x:Type vm:MainViewModel}"> <view:MainViewModel/> </DataTemplate>
  2. ViewModelLocator 패턴
<!-- App.xaml --> 
<Application.Resources>
    <vm:ViewModelLocator x:Key="Locator" />
</Application.Resources>
<!-- LoginView.xaml -->
<UserControl DataContext="{Binding LoginViewModel, Source={StaticResource Locator}}">
    <!-- View content -->
</UserControl>
  1. 코드 비하인드에서 DI 주입
public LoginView()
    {
        InitializeComponent();
        // 예: DI 컨테이너로부터 ViewModel 주입
        DataContext = Bootstrapper.ServiceProvider.GetService<LoginViewModel>();
    }

이외에도 여러 방법이 있지만 프로덕트로 설계할 때는 어떤 방법을 사용하는게 좋은지 헷갈립니다.

1 Like

DataContext Tunneling 을 활용하는 것이 좋다고 생각합니다.

1 Like

자식 ViewModel이 부모 ViewModel의 무언가를 사용할 수 있는 방식이 맞나요?
이 경우 자식이 부모에게 종속되어 mvvm에 위배된다는 생각이 들어서 여쭙습니다.

제품 특성에 따라서 어느정도 용인해야할까요?

종속 없다면,

DataContext = new ViewModel();

이렇게 하겠습니다.

1 Like

우선, 설정 우선 순위는 코드 비하인드에서의 설정이 우선합니다.

public LoginView()
{
    // XAML 요소의 DataContext attribute로부터 DataContext 속성 설정됨.
    InitializeComponent(); 

    // 재설정 => 최종적인 설정.
    DataContext = Bootstrapper.ServiceProvider.GetService<LoginViewModel>(); 
    // DataContext = new LoginViewModel(); 
}

Static Resource

말 그대로, static 합니다.
뷰가 앱의 생애 주기 동안 고정 표시된다면 뷰모델이 static 해도 상관이 없지만, 그렇지 않다면, 메모리에 깔아 둘 이유는 없을 것 같습니다.

뷰모델 객체는 해당 뷰가 없어질 때 함께 없어지는 편이 메모리 측면에서 유리할 것입니다.

식별자 위치

XAML 은 약간의 한계를 가지고 있는데, 스크립트에 식별자만 넣을 수 있을 뿐, 아래와 같이 expression 을 넣을 수 없다는 점입니다.

<Button Clicked="() => vm.DoSomething()"/>

이 점이 작게 보이지만, 코드 편집할 때, XAML, 코드 비하인드, 뷰모델 파일을 동시에 열어 놓게 만들 확률이 높습니다.

따라서, 제시하신 세 가지 방법 중 어떤 것을 선택하더라도 개발하는 과정에서는 큰 차이가 없게 됩니다.

다만, 개인적 코딩 스타일이 이벤트 핸들러보다는 Command 를 선호한다면 XAML+뷰모델 위주로 편집할 확률이 높아지므로 식별자를 XAML에 두는 편이 좋을 것입니다.

반대인 경우, 코드 비하인드에 넣는 편이 더 유리할 것 같습니다.

readonly LoginViewModel _vlewModel;
public LoginView()
{
    InitializeComponent(); 

    // LoginViewModel 은 참조형식
    DataContext = _viewModel = new LoginViewModel(); 
}

void OnStartButtonClicked(object? s, EventArgs e)
{
   // 
}
1 Like
public LoginView()
{
    // XAML 요소의 DataContext attribute로부터 DataContext 속성 설정됨.
    InitializeComponent(); 

    // 재설정 => 최종적인 설정.
    DataContext = Bootstrapper.ServiceProvider.GetService<LoginViewModel>(); 
    // DataContext = new LoginViewModel(); 
}

해당 내용이 xaml의 DataContext에서 ViewModel을 설정한 후 코드 비하인드에서 다시 설정하는건가요? 이렇게 하는 이유를 잘 모르겠습니다.

식별자를 xaml에 두는 것은 xaml의 Datacontext에서 Viewmodel을 설정하는게 맞나요??

WPF (나 기타 XAML 기반 UI 프레임워크)를 계속 사용할 것이면, InitializeComponent() 메서드가 왜 호출되는 지 알아 두시는 것이 좋을 것 같습니다.

예 맞습니다. 그것을 보고 바인딩된 객체의 형식을 알 수 있는 것이죠.