MVVM依赖注入跨平台

时间:2014-12-23 17:20:05

标签: mvvm

早些时候,我写了一个关于让我的MainViewModel实现接口的方法的问题,这取决于我在Universal App中运行的项目。

Choose interface implementation in universal app depending on platform

我已经实现了MVVM灯,这让我可以像这样注册我的VM:

SimpleIoc.Default.Register<MainViewModel>();

它还提供了在CTOR中注册具有接口的VM的机会,如下所示:

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

设置如下:

我有2个项目,Windows和WindowsPhone。 在我的VM中,它驻留在PCL中,我有我的MainViewModel,它在ctor中使用ICameraCaller。 这两个项目都有一个实现ICameraCaller的类,根据我运行的项目,我希望将CameraCaller的“正确”实现传递给CTOR。

所以我被告知DI是要走的路。对我来说这是一个相当新的话题,我已经被困了很长时间。

对我而言,这听起来应该是一个很棒的任务?根据正在运行的项目将接口的实现传递给VM。

以下是MainViewModel的代码:

private ICameraCaller _cameraCaller;

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

我不明白为什么我可以在ViewModelLocator中向我的viewmodel注册一个接口,因为我不知道将使用哪种实现。即使我知道。我无法访问其他项目中的实现。我一定是这个问题都错了。

1 个答案:

答案 0 :(得分:4)

首先:使用mvvm light MVVMLight.portable的便携版。我还建议您使用一些更高级的IoC容器 - 我个人更喜欢Ninject(也有便携版本Ninject.Portable) - 它符合我的所有需求。从Nuget Package Manager获取。

第二 - 创建名为ViewModelLocator的类(Windows Phone和Windows Modern不同),它将充当您所谓的ApplicationCore(依赖注入容器所在的位置)。

示例:

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中,将ViewModelLocator添加为StaticResource

<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中添加绑定到正确的ViewModel:

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

对Windows Phone项目重复完全相同的步骤,但在ApplicationModule中绑定到Windows Phone实现,例如:Bind<ICameraController>().To<WindowsPhoneCameraController>()

那里发生了什么?您使用名为Inversion of Control的{​​{1}}库来&#34;绑定&#34;接口到具体类。这意味着 - 当您致电Ninject并在创建对象IKernel.Get<Type>()时,请参阅构造函数Ninject中的任何位置,它将创建新的ICameraControl对象。您创建了ModernCameraControl以便存储您的&#34;依赖注入解析器&#34; (称为IKernel) - 因此您不必在任何地方使用丑陋的服务定位器模式和静态引用ViewModelLocator。当然我用简化版本描述了它 - 使用Kernel你可以做其他很棒的事情,比如作用域(例如你可以注册接口到类,这将是单例 - 在绑定的任何地方相同的对象实例),你可以添加条件逻辑正在注入课程(检查NinjectBind<T>().To<T>().WhenInjectedTo/WhenInjectedExactlyTo等)。