[wpf] ViewModelLocator는 무엇이며 DataTemplate과 비교하여 장단점은 무엇입니까?

누군가 ViewModelLocator가 무엇인지, 어떻게 작동하는지, DataTemplates와 비교하여 그것을 사용하는 장단점에 대한 간략한 요약을 줄 수 있습니까?

나는 Google에서 정보를 찾으려고 노력했지만 많은 다른 구현이 있고 그것이 무엇인지 그리고 그것을 사용하는 장단점에 대한 엄격한 목록이없는 것 같습니다.



답변

소개

MVVM에서 일반적인 관행은 뷰가 DI ( 종속성 주입 ) 컨테이너 에서 뷰를 확인하여 뷰 모델을 찾도록하는 것입니다 . 컨테이너가 View 클래스의 인스턴스를 제공 (해결)하도록 요청하면 자동으로 발생합니다. 컨테이너 는 ViewModel 매개 변수를받는 View의 생성자를 호출하여 ViewModel을 View에 주입 합니다. 이 방식을 IoC ( Inversion of Control )라고 합니다.

DI의 이점

여기서 주요 이점은 컨테이너 에서 요청한 유형을 확인하는 방법에 대한 지침을 사용하여 런타임에 구성 할 수 있다는 것입니다. 이를 통해 애플리케이션이 실제로 실행될 때 사용하는 유형 (Views 및 ViewModels)을 확인하도록 지시하고 애플리케이션에 대한 단위 테스트를 실행할 때 다르게 지시함으로써 테스트 가능성을 높일 수 있습니다. 후자의 경우 응용 프로그램에 UI가 없으므로 (실행되지 않고 테스트 만 수행됨) 컨테이너가 응용 프로그램이 실행될 때 사용되는 “일반”유형 대신 모의 를 확인합니다.

DI로 인한 문제

지금까지 우리는 DI 접근 방식이 애플리케이션 구성 요소 생성에 추상화 계층을 추가하여 애플리케이션을 쉽게 테스트 할 수 있음을 확인했습니다. 이 접근 방식에는 한 가지 문제가 있습니다. . Microsoft Expression Blend와 같은 비주얼 디자이너잘 어울리지 않는다는 것입니다 .

문제는 정상적인 애플리케이션 실행과 단위 테스트 실행 모두 에서 해결해야 할 유형에 대한 지침으로 컨테이너 를 설정해야 한다는 것입니다. 또한 누군가는 ViewModels가 그것들에 주입 될 수 있도록 View를 해결하도록 컨테이너 요청 해야합니다.

그러나 디자인 타임에는 실행중인 코드가 없습니다. . 디자이너는 리플렉션을 사용하여 뷰의 인스턴스를 만들려고합니다. 즉, 다음을 의미합니다.

  • View 생성자에 ViewModel 인스턴스가 필요한 경우 디자이너는 View를 전혀 인스턴스화 할 수 없습니다. 제어 된 방식으로 오류가 발생합니다.
  • 보기는 매개 변수가없는 생성자가있는 경우보기 인스턴스화 될 것입니다,하지만이 DataContext될 것입니다 null우리가 ‘디자이너의 “빈”보기 얻을 것이다 – 그래서 매우 유용하지 않다

ViewModelLocator 입력

ViewModelLocator는 다음과 같이 사용되는 추가 추상화입니다.

  • View 자체는 ViewModelLocator를 리소스의 일부로 인스턴스화 하고 DataContext를 로케이터의 ViewModel 속성에 데이터 바인딩합니다.
  • 로케이터 는 우리가 디자인 모드에 있는지 어떻게 든 감지합니다.
  • 디자인 모드가 아닌 경우 로케이터는 위에서 설명한대로 DI 컨테이너에서 확인하는 ViewModel을 반환합니다.
  • 디자인 모드에서 로케이터는 자체 로직을 사용하여 고정 된 “더미”ViewModel을 반환합니다 (기억 : 디자인 타임에는 컨테이너가 없습니다!). 이 ViewModel은 일반적으로 더미 데이터로 미리 채워져 있습니다.

물론 이것은 뷰에 매개 변수없는 생성자가 있어야 시작된다는 것을 의미합니다 (그렇지 않으면 디자이너가 인스턴스화 할 수 없습니다).

요약

ViewModelLocator는 MVVM 애플리케이션에서 DI의 이점을 유지하면서 코드가 비주얼 디자이너와 잘 작동 할 수 있도록하는 관용구입니다. 이를 응용 프로그램의 “혼합 가능성”이라고도합니다 (Expression Blend 참조).

위의 내용을 소화 한 후 여기 에서 실제 예를 참조 하십시오 .

마지막으로 데이터 템플릿을 사용하는 것은 ViewModelLocator를 사용하는 것의 대안이 아니라 UI의 일부에 대해 명시적인 View / ViewModel 쌍을 사용하는 것의 대안입니다. 데이터 템플릿을 대신 사용할 수 있으므로 ViewModel에 대한 뷰를 정의 할 필요가없는 경우가 많습니다.


답변

@Jon의 답변 구현 예

뷰 모델 로케이터 클래스가 있습니다. 각 속성은 뷰에 할당 할 뷰 모델의 인스턴스가됩니다. 코드가 디자인 모드에서 실행 중인지 여부를 확인할 수 있습니다 DesignerProperties.GetIsInDesignMode. 이를 통해 디자인 시간 동안 모의 모델을 사용하고 응용 프로그램을 실행할 때 실제 개체를 사용할 수 있습니다.

public class ViewModelLocator
{
    private DependencyObject dummy = new DependencyObject();

    public IMainViewModel MainViewModel
    {
        get
        {
            if (IsInDesignMode())
            {
                return new MockMainViewModel();
            }

            return MyIoC.Container.GetExportedValue<IMainViewModel>();
        }
    }

    // returns true if editing .xaml file in VS for example
    private bool IsInDesignMode()
    {
        return DesignerProperties.GetIsInDesignMode(dummy);
    }
}

그리고 그것을 사용하기 위해 App.xaml리소스에 로케이터를 추가 할 수 있습니다 .

xmlns:core="clr-namespace:MyViewModelLocatorNamespace"

<Application.Resources>
    <core:ViewModelLocator x:Key="ViewModelLocator" />
</Application.Resources>

그런 다음 뷰 (예 : MainView.xaml)를 뷰 모델에 연결하려면 :

<Window ...
  DataContext="{Binding Path=MainViewModel, Source={StaticResource ViewModelLocator}}">


답변

이 질문의 다른 답변이 디자이너를 둘러싼 이유를 이해하지 못합니다.

View Model Locator의 목적은 View가 이것을 인스턴스화 할 수 있도록하는 것입니다 (예, View Model Locator = View First).

public void MyWindowViewModel(IService someService)
{
}

이 대신 :

public void MyWindowViewModel()
{
}

이것을 선언함으로써 :

DataContext="{Binding MainWindowModel, Source={StaticResource ViewModelLocator}}"

ViewModelLocatorIoC를 참조하는 클래스는 어디에 있으며 MainWindowModel그것이 노출 하는 속성을 해결하는 방법 입니다.

뷰에 모의 뷰 모델을 제공하는 것과는 관련이 없습니다. 원한다면 그냥 해

d:DataContext="{d:DesignInstance MockViewModels:MockMainWindowModel, IsDesignTimeCreatable=True}"

View Model Locator는 예를 들어 Unity와 같은 일부 (모든) Inversion of Control 컨테이너를 둘러싼 래퍼입니다.

인용하다:


답변