답변:
MVVM에서 일반적인 관행은 뷰가 DI ( 종속성 주입 ) 컨테이너 에서 뷰를 확인하여 뷰 모델을 찾도록하는 것입니다 . 컨테이너가 View 클래스의 인스턴스를 제공 (해결)하도록 요청하면 자동으로 발생합니다. 컨테이너 는 ViewModel 매개 변수를받는 View의 생성자를 호출하여 ViewModel을 View에 주입 합니다. 이 방식을 IoC ( Inversion of Control )라고 합니다.
여기서 주요 이점은 컨테이너 에서 요청한 유형을 확인하는 방법에 대한 지침을 사용하여 런타임에 구성 할 수 있다는 것입니다. 이를 통해 애플리케이션이 실제로 실행될 때 사용하는 유형 (Views 및 ViewModels)을 확인하도록 지시하고 애플리케이션에 대한 단위 테스트를 실행할 때 다르게 지시함으로써 테스트 가능성을 높일 수 있습니다. 후자의 경우 응용 프로그램에 UI가 없으므로 (실행되지 않고 테스트 만 수행됨) 컨테이너가 응용 프로그램이 실행될 때 사용되는 "일반"유형 대신 모의 를 확인합니다.
지금까지 우리는 DI 접근 방식이 애플리케이션 구성 요소 생성에 추상화 계층을 추가하여 애플리케이션을 쉽게 테스트 할 수 있음을 확인했습니다. 이 접근 방식에는 한 가지 문제가 있습니다. . Microsoft Expression Blend와 같은 비주얼 디자이너 와 잘 어울리지 않는다는 것입니다 .
문제는 정상적인 애플리케이션 실행과 단위 테스트 실행 모두 에서 해결해야 할 유형에 대한 지침으로 컨테이너 를 설정해야 한다는 것입니다. 또한 누군가는 ViewModels가 그것들에 주입 될 수 있도록 View를 해결하도록 컨테이너 요청 해야합니다.
그러나 디자인 타임에는 실행중인 코드가 없습니다. . 디자이너는 리플렉션을 사용하여 뷰의 인스턴스를 만들려고합니다. 즉, 다음을 의미합니다.
DataContext
될 것입니다 null
우리가 '디자이너의 "빈"보기 얻을 것이다 - 그래서 매우 유용하지 않다ViewModelLocator는 다음과 같이 사용되는 추가 추상화입니다.
물론 이것은 뷰에 매개 변수없는 생성자가 있어야 시작된다는 것을 의미합니다 (그렇지 않으면 디자이너가 인스턴스화 할 수 없습니다).
ViewModelLocator는 MVVM 애플리케이션에서 DI의 이점을 유지하면서 코드가 비주얼 디자이너와 잘 작동 할 수 있도록하는 관용구입니다. 이를 응용 프로그램의 "혼합 가능성"이라고도합니다 (Expression Blend 참조).
위의 내용을 소화 한 후 여기 에서 실제 예를 참조 하십시오 .
마지막으로 데이터 템플릿을 사용하는 것은 ViewModelLocator를 사용하는 것의 대안이 아니라 UI의 일부에 대해 명시적인 View / ViewModel 쌍을 사용하는 것의 대안입니다. 데이터 템플릿을 대신 사용할 수 있으므로 ViewModel에 대한 뷰를 정의 할 필요가없는 경우가 많습니다.
d:DataContext="{d:DesignInstance MockViewModels:MockMainWindowModel, IsDesignTimeCreatable=True}"
. 로케이터의 목적은 실제로 뷰에서 DI를 활성화하는 것입니다. WPF는이를 제공하는 데 너무 나쁘기 때문입니다. 예 : 일부 대화창을 여는 메인 창이 있습니다. 일반적인 방법으로 대화 창에서 DI를 해결하려면 주 창에 대한 종속성으로 전달해야합니다! 이것은 View Locator로 피할 수 있습니다.
@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
있습니까?
이 질문의 다른 답변이 디자이너를 둘러싼 이유를 이해하지 못합니다.
View Model Locator의 목적은 View가 이것을 인스턴스화 할 수 있도록하는 것입니다 (예, View Model Locator = View First).
public void MyWindowViewModel(IService someService)
{
}
이 대신 :
public void MyWindowViewModel()
{
}
이것을 선언함으로써 :
DataContext="{Binding MainWindowModel, Source={StaticResource ViewModelLocator}}"
ViewModelLocator
IoC를 참조하는 클래스는 어디에 있으며 MainWindowModel
그것이 노출 하는 속성을 해결하는 방법 입니다.
뷰에 모의 뷰 모델을 제공하는 것과는 관련이 없습니다. 원한다면 그냥 해
d:DataContext="{d:DesignInstance MockViewModels:MockMainWindowModel, IsDesignTimeCreatable=True}"
View Model Locator는 예를 들어 Unity와 같은 일부 (모든) Inversion of Control 컨테이너를 둘러싼 래퍼입니다.
인용하다: