早些时候,我写了这个问题,关于让我的 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 中添加您的
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 中添加绑定(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/WhenInjectedExactlyTo
,Bind<T>().ToMethod(..)
等。 )。
关于MVVM 依赖注入(inject)跨平台,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27625091/