尝试使用MVVM模式回填WPF应用程序以使用依赖项注入。我并不过分熟悉DI,之前只使用过一次,但我认为我理解所涉及的原则。
我需要确保绑定都在一个地方注册 - 应用程序根目录。在WPF中,这是OnStartup方法。所以,我抓住Ninject并把它扔进我的应用程序,尝试自动将我的存储库类绑定到初始视图:
private void OnStartup(object sender, StartupEventArgs e)
{
IKernel kernel = new StandardKernel();
kernel.Bind<IRepository>().To<Repository>();
Views.MainView view = new Views.MainView();
view.DataContext = kernel.Get<ViewModels.MainViewModel>();
view.Show();
}
从此处开始,我使用数据模板资源设置上下文:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:views="clr-namespace:My.Views"
xmlns:models="clr-namespace:My.ViewModels" >
<DataTemplate DataType="{x:Type models:MyViewModel}" >
<views:MyView />
</DataTemplate>
<!-- etc -->
</ResourceDictionary>
它有效。大!但是,在MainViewModel中,我按下一个按钮并将不同类型的ViewModel加载到窗口中:
NavigationHelper.NewWindow(this, new QuoteViewModel(quote, new Repository()));
这行代码正是我首先把我带到DI的地方 - 我无法测试这个,因为我不能在这里嘲笑依赖。在这个例子中添加DI根本不能帮助我,因为我只想在OnStartUp中使用我的IoC容器,所以我不能使用kernel.Get来获取我的QuoteViewModel,对吗?
窥探我的情况我看到有很多人建议我使用服务定位器来解决这个问题。这对我来说是新的,我也看到很多人告诉我,将它用于DI是一种反模式,不应该用bargepole触及。谁没错?
也许更重要的是,这个问题有一个简洁的解决方案吗?我已经看到了其他一些需要不同软件包的大杂烩才能使其发挥作用的例子。现在,感觉MVVM和DI并不是为了让彼此玩得很好。
答案 0 :(得分:3)
你快到了。你错过了两件事:
您需要一个能够为您创建子VM的工厂。为这个工厂引入一个接口,这样你就可以在测试中替换它。
public interface IVmFactory {
IQuoteViewModel CreateQuoteViewModel();
}
您可以自己or let NInject do it for you实现此界面。
请务必在DI容器中注册此工厂,以便容器在收到实例化具有工厂依赖性的类的请求时能够解析它。
ViewModels.MainViewModel
现在,您可以使用标准构造函数注入将IVmFactory
注入到视图模型中:
public class MainViewModel {
public MainViewModel(IVmFactory vmFactory) {
_vmFactory = vmFactory;
}
// ...
}
一旦你找到了解决WPF默认构造函数问题的方法(当你试图让WPF实例化虚拟机时),DI和MVVM就可以很好地协同工作。
DI显然不是反模式,but service locator is。不幸的是,服务定位器通常与MVVM一起推荐,因为它使您能够快速入门,而无需创建工厂并正确注入它们。权衡是要快速开始,而不是干净利落。可测试的设计 - 自己决定。
答案 1 :(得分:-1)
我同意服务定位器是一种反模式,我个人通过为StandardKernel(Injector)创建一个包装类来解决这个问题,该类实现了一个接口(IInjector),然后通过字段注入将其自身注入需要它的类中: / p>
[Inject] public IInjector Injector {get; set;}
void MyClassMethod()
{
var instance = this.Injector.Get<ISomeInterface>();
// etc
}
这消除了服务位置反模式,并且还抽象了DI框架的特定于实现的细节。