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


112

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

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

답변:


204

소개

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에 대한 뷰를 정의 할 필요가없는 경우가 많습니다.


4
좋은 설명을 위해 +1. 뷰와 리소스를 더 확장 할 수 있습니까? 리소스 란보기의 속성을 의미합니까? 또는? 이 패턴에 대한 구체적인 예가있는 링크가 있습니까?
Metro Smurf 2011 년

@MetroSmurf : 링크는 요약 섹션에 있습니다.

1
감사. ViewModelLocator 사용에 제한이 있습니까? 정적 리소스를 참조한다는 사실에 대해 약간의 우려가있었습니다. 런타임에 ViewModels를 동적으로 만들 수 있습니까? 그리고 하나를 연결하는 것과 관련된 추가 코드가 많이 있습니까?
Rachel

@Rachel : 요약에있는 동일한 링크는 실용적인 예를 통해 이러한 질문에 답해야합니다.
Jon

2
매우 오해의 소지가있는 답변입니다. View Model Locator의 주요 목적은 디자이너에게 더미 데이터를 제공하는 것이 아닙니다. 을 지정하여 쉽게 수행 할 수 있습니다 d:DataContext="{d:DesignInstance MockViewModels:MockMainWindowModel, IsDesignTimeCreatable=True}". 로케이터의 목적은 실제로 뷰에서 DI를 활성화하는 것입니다. WPF는이를 제공하는 데 너무 나쁘기 때문입니다. 예 : 일부 대화창을 여는 메인 창이 있습니다. 일반적인 방법으로 대화 창에서 DI를 해결하려면 주 창에 대한 종속성으로 전달해야합니다! 이것은 View Locator로 피할 수 있습니다.
hyankov

10

@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}}">

this대신 사용하는 데 차이 가 dummy있습니까?
Sebastian Xawery Wiśniowiecki

5

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

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 컨테이너를 둘러싼 래퍼입니다.

인용하다:


뷰 모델 로케이터에는 컨테이너가 필요하지 않으며 사용자가 구성을 통해 뷰 모델을 확인하는 방법을 결정하고 컨테이너를 사용하거나 유형을 새로 만들 수 있습니다. 따라서 예를 들어 일부 컨테이너의 모든 뷰 및 뷰 모델을 사전 등록하는 대신 규칙 기반 뷰 모델 위치를 수행 할 수 있습니다.
Chris Bordeman

당신은 " 나는 왜 다른 대답이 [...] 디자이너를 감싸는 지 이해하지 못한다 "라고 말할 때 옳다 . 그러나 로케이터의 요점은 뷰 모델이 어떤 것인지에 대한 지식을 뷰에서 제거하는 것이다. 뷰를이 인스턴스화와 독립적으로 만들어 로케이터에 남겨 둡니다. 로케이터는 뷰 모델의 다양한 특징을 제공 할 수있을 것입니다. 아마도 로케이터가 관리 할 플러그인을 통해 추가 된 일부 사용자 지정 항목 (및 디자인 타임에 대한 특정 항목)을 제공 할 수 있습니다. 뷰는 뷰 모델의 올바른 버전을 찾는이 프로세스를 모두 제거 할 것입니다. 이는 SoC에 정말 좋습니다.
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.