2014-12-23 6 views
1

이전에 내 UniversalView에서 실행중인 프로젝트에 따라 MainViewModel에서 인터페이스를 구현하는 방법에 관해이 질문을했습니다.MVVM Dependency Injection 크로스 플랫폼

Choose interface implementation in universal app depending on platform

내가 가진이 나를 이렇게 내 VM's을 등록 할 수 있습니다 MVVM 빛 구현 후 :

SimpleIoc.Default.Register<MainViewModel>(); 

그것은 또한 ctor에의 인터페이스 등으로 VM을 등록 할 oppurtunity을 제공을 이 :

SimpleIoc.Default.Register<IDataService, DataService>(); 

셋업은 다음과 같다 :

나는 2 개의 프로젝트, Windows와 WindowsPhone이있다. PCL에있는 내 VM에 ctor에서 ICameraCaller를 사용하는 MainViewModel이 있습니다. 프로젝트에는 모두 ICameraCaller를 구현하는 클래스가 있으며 어떤 프로젝트를 실행하는지에 따라 CameraCaller의 "올바른"구현을 CTOR에 전달하고 싶습니다.

저는 DI가 갈 길이라고 들었습니다. 이것은 나를위한 상당히 새로운 주제이고 나는 오랫동안 붙어 있었어.

나에게 그것은 꽤 comman 작업이어야하는 것처럼 들린다? 실행중인 프로젝트에 따라 인터페이스 구현을 VM에 전달합니다. 여기

은 MainViewModel의 ctor에 있습니다 :

private ICameraCaller _cameraCaller; 

public MainViewModel(ICameraCaller cameraCaller) 
{ 
    _cameraCaller = cameraCaller; 
} 

이해가 안 어떻게 그 가능 제가 사용되는 그 무엇을 구현 모르는 고려 ViewModelLocator 내 뷰 모델에 인터페이스를 등록하는 방법에 대한 . 내가 알았더라도. 다른 프로젝트의 구현에 액세스 할 수 없습니다. 나는이 문제를 완전히 잘못 알고 있어야합니다.

답변

4

우선 : mvvm 표시 등 MVVMLight.portable의 휴대용 버전을 사용하십시오. 나는 또한 좀 더 고급 IoC 컨테이너를 사용하는 것이 좋습니다 - 개인적으로는 Ninject (또한 휴대용 버전은 Ninject.Portable)을 선호합니다 - 내 모든 필요에 맞는. Nuget Package Manager에서 가져 오기.

ViewModelLocator (Windows Phone 및 Windows Modern과 다른 클래스)이라는 두 번째 클래스는 소위 ApplicationCore (종속성 주입 컨테이너가있는 곳) 역할을합니다.

예 : 적절한 뷰 모델에 바인딩을 추가 할

<Application 
x:Class="YourApp.App" 
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
xmlns:local="using:YouNamespace" 
xmlns:viewModel="using:ViewModelLocatorNamespace"> 

<Application.Resources> 
    <ResourceDictionary> 

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

그리고 당신의 MAINVIEW에 :

public class ViewModelLocator 
{ 
    private readonly IKernel _dependenciesContainer; 

    public ViewModelLocator() 
    { 
     _dependenciesContainer = new StandardKernel(new ApplicationKernelModule()); 
    } 

    public MainViewModel Main { get { return _dependenciesContainer.Get<MainViewModel>() } } 
} 

public class ApplicationKernelModule : NinjectModule 
{ 
    public override void Load() 
    { 
     Bind<ICameraCaller>().To<DesktopCameraCaller>(); 
    } 
} 

public class DesktopCameraCaller : ICameraCaller 
{ 
    // here lies Windows Modern implementation of camera caller 
} 

App.xaml에 ViewModelLocatorStaticResource로 추가

DataContext={Binding Source={StaticResource ViewModelLocator}, Path=Main} 

Windows Phone 프로젝트에서 똑같은 단계를 반복하십시오. 그러나 ApplicationModule에서 Windows Phone 구현에 바인드합니다 (예 : Bind<ICameraController>().To<WindowsPhoneCameraController>()).

어떻게 될까요? Ninject이라는 라이브러리 Inversion of Control을 사용하여 인터페이스를 구체적인 클래스에 "바인딩"합니다. 즉, IKernel.Get<Type>()이라고 부르면 객체 Ninject을 생성하는 동안 생성자 ICameraControl의 어느 곳에서나 볼 수 있습니다. 그러면 새로 생성되는 ModernCameraControl 객체가 생성됩니다. ""을 작성하여 "Dependency Injection Resolver"(IKernel이라고 함)를 저장할 수 있습니다. 따라서 추한 서비스 로케이터 패턴과 Kernel에 대한 정적 참조를 사용할 필요가 없습니다. 물론 단순화 된 버전으로 설명했는데 - Ninject으로 범위 지정과 같은 다른 멋진 작업을 수행 할 수 있습니다 (예 : 바인딩 된 모든 곳의 동일한 객체 인스 턴션). 클래스를 삽입하는 동안 조건부 논리를 추가 할 수 있습니다. (Bind<T>().To<T>().WhenInjectedTo/WhenInjectedExactlyTo, Bind<T>().ToMethod(..) 등을 확인하십시오).

+0

와우! 좋은 답변을 해주셔서 감사합니다! Im 시도해보십시오! . – user2915962

+1

@ user2915962 어떤 것이 명확하지 않거나 작동하지 않는지 묻고 싶습니다. – fex

+0

@ user2915962 코드를 시도하고 문서를 보지 않고이 질문에 대답했습니다.) – fex