代码之家  ›  专栏  ›  技术社区  ›  Scott Weinstein

WPF应用程序是否可以进行依赖注入?

  •  34
  • Scott Weinstein  · 技术社区  · 16 年前

    我在看 autofac 对于我的国际奥委会集装箱,但我认为这对这次讨论来说并不太重要。

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

    我正在努力的是如何将视图模型和服务分解为用户控件?用户控件是通过XAML标记实例化的,因此没有机会 Resolve() 他们。

    我能想到的最好的方法是将容器放在一个单独的容器中,让用户控件从全局容器解析它们的视图模型。这感觉就像是一个半途而废的解决方案,充其量,因为它仍然需要我的组件依赖于ServiceLocator。

    WPF是否可以提供完整的IoC?

    [编辑]-有人建议使用Prism,但即使对Prism进行评估也似乎是一项巨大的投资,我希望能有更小的投资

    [编辑]这是我被阻止的代码片段

        //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>();
    
    9 回复  |  直到 7 年前
        1
  •  16
  •   sduplooy    14 年前

    其实很容易做到。正如jedidja提到的,我们在Prism中有这样的例子。您可以将ViewModel与视图一起注入,也可以将ViewModel与视图一起注入。在Prism stocktraderi中,您将看到我们将视图注入ViewModel。实际上发生的是视图(和视图接口)有一个模型属性。该属性在codebhind中实现,以将DataContext设置为该值,例如: this.DataContext = value; . 在ViewModel的构造函数中,视图被注入。然后就开始了 View.Model = this; 它将自身作为数据上下文传递。

    我在Jeremy Miller和我在Kaizenconf上的单独演示模式的视频记录中对此做了更多的讨论。第一部分可以在这里找到 http://www.vimeo.com/2189854 .

    希望能帮上忙, 格伦

        2
  •  9
  •   user30493    16 年前

    我想你已经谈到这个问题了。控件需要注入到其父控件中,而不是通过XAML以声明方式创建。

    为了让DI工作,DI容器应该创建接受依赖项的类。这意味着父控件在设计时不会有子控件的任何实例,并且看起来像设计器中的shell。这是 可能 建议的方法。

    另一种“替代方法”是从控件的构造函数或类似的东西调用全局静态容器。有一种常见的模式,其中声明了两个构造函数,一个具有用于构造函数注入的参数列表,另一个没有委托的参数:

    // For WPF
    public Foo() : this(Global.Container.Resolve<IBar>()) {}
    
    // For the rest of the world
    public Foo(IBar bar) { .. }
    

    我几乎可以称之为反模式,但事实上有些框架别无选择。

    我甚至不是半个WPF专家,所以我在这里期待一份健康的downmod:)但希望这能有帮助。Autofac组(从主页链接)可能是另一个提出此问题的地方。Prism或MEF示例应用程序(其中包括一些WPF示例)应该让您了解什么是可能的。

        3
  •  5
  •   Jedidja    16 年前
        4
  •  3
  •   mookid8000    16 年前

    你应该看看 Caliburn -它是一个简单的WPF/Silverlight MVC框架,支持完整的DI。它看起来很酷,可以让你使用任何你想要的IoC容器。上面有几个例子 documentation wiki

        5
  •  3
  •   Jordan S. Jones    12 年前

    我们遇到了一个类似的问题,我们正在期待一个能够在Expression Blend 2.0(强类型)下提供设计时支持的解决方案。另外,我们还期待着在Expression Blend下提供一些Mock+自动生成的数据样本的解决方案。

    当然,我们也希望所有这些都能使用IOC模式。

    Paul Stovell作为一篇有趣的文章开始: http://www.paulstovell.com/blog/wpf-dependency-injection-in-xaml

    因此,我尝试在设计时添加对绑定和模拟对象的更有价值的设计时支持,现在我的大部分问题都与在视图(代码)和模型视图(Xaml)之间建立强类型连接有关,我尝试了两种方案:

    public class MyDotNetcomponent&lt;T&gt; : SomeDotNetcomponent
    {
        // Inversion of Control Loader…
        // Next step add the Inversion of control manager plus
        // some MockObject feature to work under design time
        public T View {Get;}
    }
    

    这个解决方案不起作用,因为Blend不支持通用的inside is设计图面,但Xaml确实有一些,在运行时很好,但在设计时不起作用;

    2.)解决方案2:ObjectDataProvider

    <ObjectDataProvider ObjectType="{x:Type CP:IFooView}" />
    <!-- Work in Blend -->
    <!—- IOC Issue: we need to use a concrete type and/or static Method there no way to achive a load on demande feature in a easy way -->
    

    <CWD:ServiceObjectDataProvider ObjectType="{x:Type CP:IFooView}" />
    <!-- Cannot inherit from ObjectDataProvider to achive the right behavior everything is private-->
    

    4.)解决方案4:从头到作业创建模拟ObjectDataProvider

    <CWD:ServiceObjectDataProvider ObjectType="{x:Type CP:IFooView }" />
    <!-- Not working in Blend, quite obvious-->
    

    <CWM:ServiceMarkup MetaView="{x:Type CP:IFooView}"/>
    <!-- Not working in Blend -->
    

    当我说不在blend中工作时,为了澄清一点,我的意思是绑定对话框不可用,设计器需要自己手工编写XAML。

    我们下一步可能需要花时间来评估为Expression Blend创建插件的能力。

        6
  •  2
  •   Justin Bozonier    16 年前

    是的,我们总是这样做。您可以将ViewModel“注入”到控件的DataContext中。

    实际上,我发现WPF更容易与DI一起使用。甚至依赖关系对象和属性也可以无缝地与之协同工作。

        7
  •  1
  •   Ben Stabile    11 年前

    MVVM公司 使用的解决方案 数据上下文

    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    mc:Ignorable="d" 
    d:DataContext="{d:DesignInstance Type=local:MyViewModelMock, IsDesignTimeCreatable=True}"
    

    在您的视图中,可以有一个属性getter,它将 数据上下文 到您期望的类型(只是为了更容易在后面的代码中使用)。

    private IMyViewModel ViewModel { get { return (IMyViewModel) DataContext; } }
    

    接口

    一般来说,您不应该从解决方案中的所有容器中解决问题。实际上,在每个构造函数中传递容器或使其全局可访问被认为是不好的做法。(您应该查阅关于“服务定位器”策略为何构成“反模式”的讨论)。

    创建一个公共视图构造函数,该构造函数具有容器(如Prism Unity或MEF)可以解析的显式依赖关系。

    如果需要,还可以创建 内部的 用于创建视图模型的模拟的默认构造函数(或实际的)。这样可以防止无意中使用” 设计建造师 “外部(在你的“壳”或任何地方)。您的测试项目也可以使用这样的构造函数 “在” ". 当然,这通常是不必要的,因为无论如何,您都可以使用完全依赖构造函数注入mock,并且因为您的大多数测试应该集中在 首先。中的任何代码 查看 (如果您的视图需要大量测试,那么您可能会问自己为什么!)

    格伦还提到你可以注射 ,或 . 我更喜欢后者,因为有非常好的技术可以分离一切(使用声明性绑定、命令、事件聚合、中介模式等)。这个 视图模型 所有的繁重工作都将在这里完成,以协调核心业务逻辑。如果所有必要的“绑定”点都由 视图模型 ,它真的不需要知道 任何东西 关于 (在XAML中,可以声明性地连接到它)。

    如果我们使视图模型与用户交互的源不可知,那么测试就容易得多(最好是首先测试)。这也意味着您可以轻松地插入任何视图(WPF、Silverlight、ASP.NET、Console等)。事实上,为了确保实现适当的分离,我们可以问自己“MVM”(Model ViewModel)架构是否可以在工作流服务的上下文中工作。当你停下来想一想的时候,你的大部分单元测试可能都是在这个前提下设计的。

        8
  •  0
  •   satish    14 年前

    我认为你必须先决定视图还是视图模型,然后给出另一个答案。。有几个开源框架也这样做。我使用Caliburn,首先使用ViewModel,这是一个非常好的方法

        9
  •  0
  •   ThinkingStiff    12 年前

    我编写了一个非常轻量级的框架,其中ViewModel在运行时通过使用IoC(Unity)作为标记扩展来解析。

    该框架允许在没有代码的情况下编写XAML,但仍然允许您路由命令、数据绑定和事件处理程序。

    无论如何,我认为您不需要在您的情况下使用松散的XAML,但是如果您查看代码( http://xtrememvvm.codeplex.com