WPF应用程序可以进行依赖注入吗? [英] Is Dependency Injection possible with a WPF application?

查看:418
本文介绍了WPF应用程序可以进行依赖注入吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想开始在WPF应用程序中使用依赖项注入,主要是为了获得更好的单元可测试性.我的应用主要是按照M-V-VM模式构建的. 我正在为我的IoC容器查看 autofac ,但我认为这并不重要对于这个讨论来说太多了.

将服务注入到开始窗口似乎很简单,因为我可以创建容器并在App.xaml.cs中从中解析.

我正在苦苦挣扎的是如何将ViewModels和Services DI到用户控件中?用户控件通过XAML标记实例化,因此没有机会Resolve().

我能想到的最好的方法是将容器放置在Singleton中,并让用户控件从全局容器中解析其ViewModels.充其量,这似乎是一个半途而废的解决方案,因为它仍然需要我的组件依赖ServiceLocator.

使用WPF是否可以实现完整的IoC?

[edit]-已建议使用棱镜,但即使对棱镜进行评估似乎也是一笔巨大的投资,但我希望有一些小的选择

[edit]这是我停下来的代码片段

    //setup IoC container (in app.xaml.cs)
    var builder = new ContainerBuilder();
    builder.Register<NewsSource>().As<INewsSource>();
    builder.Register<AViewModel>().FactoryScoped();
    var container = builder.Build();

    // in user control ctor -
    // this doesn't work, where do I get the container from
    VM = container.Resolve<AViewModel>();

    // in app.xaml.cs
    // this compiles, but I can't use this uc, 
    //as the one I want in created via xaml in the primary window
    SomeUserControl uc = new SomeUserControl();
    uc.VM = container.Resolve<AViewModel>();

解决方案

实际上很容易做到.正如jedidja提到的,我们在Prism中有这样的例子.您既可以将ViewModel注入View,也可以将View注入ViewModel.在Prism StockTraderRI中,您将看到我们将View注入到ViewModel中.本质上发生的事情是View(和View界面)具有Model属性.该属性在后面的代码中实现,以将DataContext设置为该值,例如:this.DataContext = value;.在ViewModel的构造函数中,将注入View.然后,它设置View.Model = this;,它将自己作为DataContext传递.

您还可以轻松地进行相反操作,并将ViewModel注入到View中.我实际上更喜欢这样做,因为这意味着ViewModel根本不再具有对该视图的任何反向引用.这意味着在对ViewModel进行单元测试时,您甚至都没有Mock的视图.此外,它还使代码更简洁,因为在View的构造函数中,它只是将DataContext设置为注入的ViewModel.

我和杰里米·米勒(Jeremy Miller)在Kaizenconf上发表的独立演示模式"演讲的录像中,我对此进行了更多讨论.的第一部分可以在这里 http://www.vimeo.com/2189854 .. >

希望这会有所帮助, 格伦

I want to start using dependency injection in my WPF application, largely for better unit testability. My app is mostly constructed along the M-V-VM pattern. I'm looking at autofac for my IoC container, but I don't think that matters too much for this discussion.

Injecting a service into the start window seems straightforward, as I can create the container and resolve from it in App.xaml.cs.

What I'm struggling with is how I can DI ViewModels and Services into User Controls? The user controls are instantiated via XAML markup, so there's no opportunity to Resolve() them.

The best I can think of is to place the container in a Singleton, and have the user controls resolve their ViewModels from the global container. This feels like a half-way solution, at best, as it still required my components to have a dependency on a ServiceLocator.

Is full IoC possible with WPF?

[edit] - Prism has been suggested, but even evaluating Prism seems like a big investment, I'm hoping for something smaller

[edit] here's a code fragment where I'm stopped

    //setup IoC container (in app.xaml.cs)
    var builder = new ContainerBuilder();
    builder.Register<NewsSource>().As<INewsSource>();
    builder.Register<AViewModel>().FactoryScoped();
    var container = builder.Build();

    // in user control ctor -
    // this doesn't work, where do I get the container from
    VM = container.Resolve<AViewModel>();

    // in app.xaml.cs
    // this compiles, but I can't use this uc, 
    //as the one I want in created via xaml in the primary window
    SomeUserControl uc = new SomeUserControl();
    uc.VM = container.Resolve<AViewModel>();

解决方案

It's actually very easy to do. We have examples of this in Prism as jedidja mentioned. You can either have the ViewModel get injected with the View or the View get injected with the ViewModel. In the Prism StockTraderRI you will see that we inject the View into the ViewModel. Essentially what happens is that the View (and View interface) has a Model property. That property is implemented in the codebehind to set the DataContext to the value, for example: this.DataContext = value;. In the constructor of the ViewModel, the View gets injected. It then sets View.Model = this; which will pass itself as the DataContext.

You can also easily do the reverse and have the ViewModel injected into the View. I actually prefer this because it means that the ViewModel no longer has any back reference to the view at all. This means when unit-testing the ViewModel you don't have a view to even Mock. Additionally it makes the code cleaner, in that in the constructor of the View, it simply sets the DataContext to the ViewModel that was injected.

I talk a bit more about this in the video recording of the Separated Presentation Patterns talk that Jeremy Miller and I gave at Kaizenconf. The first part of which can be found here http://www.vimeo.com/2189854.

Hope this helps, Glenn

这篇关于WPF应用程序可以进行依赖注入吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆