MVVM 依赖注入(inject)跨平台

标签 mvvm

早些时候,我写了这个问题,关于让我的 MainViewModel 实现接口(interface)的方法,具体取决于我的通用应用程序中运行的项目。

Choose interface implementation in universal app depending on platform

在此之后我实现了 MVVM 灯,它让我可以像这样注册我的虚拟机:

SimpleIoc.Default.Register<MainViewModel>();

它还提供了使用 CTOR 中的接口(interface)注册 VM 的机会,如下所示:
SimpleIoc.Default.Register<IDataService, DataService>();

设置如下:

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

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

对我来说,这听起来应该是一项非常普通的任务?根据正在运行的项目将接口(interface)的实现传递给 VM。

这是 MainViewModel 的 ctor:
private ICameraCaller _cameraCaller;

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

考虑到我不知道将使用什么实现,我不明白如何在 ViewModelLocator 中向我的 View 模型注册一个接口(interface)。即使我知道。我无法访问其他项目中的实现。我必须解决这个问题都错了。

最佳答案

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

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

例子:

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 :
<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 中添加绑定(bind)到正确的 ViewModel:
DataContext={Binding Source={StaticResource ViewModelLocator}, Path=Main}

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

那里会发生什么?您使用 Inversion of Control名为 Ninject 的库将接口(interface)“绑定(bind)”到具体的类中。这意味着 - 当您调用 IKernel.Get<Type>() 时在创建对象时 Ninject查看构造函数中的任何位置ICameraControl它将在那里创建新的ModernCameraControl目的。您创建了 ViewModelLocator做一个简单的地方来存储你的“依赖注入(inject)解析器”(称为 IKernel)——所以你不必使用丑陋的服务定位器模式和对 Kernel 的静态引用到处。当然,我用简化版描述了它 - 使用 Ninject你可以做其他很棒的事情,比如作用域(例如,你可以将接口(interface)注册到单例的类 - 绑定(bind)的任何地方都可以插入相同的对象),你可以在注入(inject)类时添加条件逻辑(检查 Bind<T>().To<T>().WhenInjectedTo/WhenInjectedExactlyToBind<T>().ToMethod(..) 等。 )。

关于MVVM 依赖注入(inject)跨平台,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27625091/

相关文章:

c# - WPF 中排队事件的最佳实践

mvvm - 使用 MVVM 进行 Windows Mobile 开发

c# - 是否可以使用 for/while 循环创建 MVVM 属性?

c# - 为什么我的 XAML 交互行为在用户控件中不起作用

c# - MVVM - 按钮命令绑定(bind)不起作用

c# - 来自主窗口文本框的用户控件文本框内的 wpf 绑定(bind)文本

c# - 如何在 Canvas 上旋转动态创建的 ListBoxItem?

WPF/MVVM - View 模型是否应该保持不变而只是模型发生变化?

c# - 使用MVVM,如何使用App.config动态生成 View

.net - WPF MVVM 从 ViewModel 触发事件的正确方法