问题 Prism,将Views和ViewModels与Unity连接,试图理解它


使用Unity创建视图和视图模型

使用Unity作为依赖注入容器与使用类似   MEF,以及基于属性和基于构造函数的注入   支持的。主要区别在于类型通常是   在运行时没有隐含发现;相反,他们必须   在容器中注册。

通常,您在视图模型上定义一个接口,以便视图   模型的特定具体类型可以与视图分离。对于   例如,视图可以通过a定义其对视图模型的依赖性   构造函数参数,如此处所示。 C#

public QuestionnaireView() 
{
    InitializeComponent(); 
}

public QuestionnaireView(QuestionnaireViewModel viewModel) : this() 
{
    this.DataContext = viewModel;
}

默认参数少   构造函数是必要的,以允许视图在设计时工作   工具,例如Visual Studio和Expression Blend。

或者,您可以在上面定义只写视图模型属性   查看,如此处所示。 Unity将实例化所需的视图模型   在实例化视图后调用属性setter。 C#

public QuestionnaireView() 
{
    InitializeComponent(); 
}

[Dependency] 
public QuestionnaireViewModel ViewModel 
{
    set { this.DataContext = value; } 
}

视图模型类型已在Unity容器中注册,如图所示   这里。 C#

IUnityContainer container;
container.RegisterType<QuestionnaireViewModel>();

然后可以通过容器实例化视图,如图所示   这里。 C#

IUnityContainer container;
var view = container.Resolve<QuestionnaireView>();
  1. 如果我省略了有关注册ViewModel和实例化View的代码的最后部分,并且只使用将ViewModel挂钩到View的两种方法中的任何一种(使用构造函数或使用属性),那么看起来是ViewModel和View似乎一切都运转良好。那么代码注册ViewModel并实例化View的需求是什么?

  2. 第一个例子,使用构造函数钩住View和ViewModel,没有提到Unity的全部,所以Unity实际上在这里使用了吗?

  3. 使用基于属性的注射比使用基于构造的注射有任何优势还是它们完全相同?

  4. 文本的第一部分说“*通常,您在视图模型上定义一个接口,以便视图模型的特定具体类型可以与视图分离”,然后给出一个示例。然而,这个例子根本没有提到接口。这里发生了什么,我错过了什么?


3053
2017-12-23 14:40


起源

我喜欢使用Microsoft的Prism库,但我觉得他们使用Views进行导航的例子是一个坏主意,因为我认为ViewModels应该在使用MVVM设计模式而不是视图时控制应用程序流。如果你在你的应用程序中尝试使用MVVM,我会建议你 ApplicationViewModel 它处理窗口管理,让WPF通过DataTemplates解析要使用的View。 - Rachel


答案:


回答问题1和4

在您的示例中,viewmodel是类型 QuestionnaireViewModel,这是一个具体的课程。因为它是一个具体的类,当您使用时解析视图 container.Resolve<QuestionnaireView>(),unity将通过调用为您实例化viewmodel container.Resolve<QuestionnaireViewModel>() 在幕后。

在这种情况下,注册viewmodel是多余的。但是,在使用依赖注入时,您通常希望使用接口而不是类,因此构造函数看起来像这样:

public QuestionnaireView(IQuestionnaireViewModel viewModel)
{
    this.DataContext = viewModel;
}

既然你的构造函数接收了一个接口而不是一个类作为参数,Unity就不知道你想要使用哪个接口实现。要告诉Unity,您需要将viewmodel注册到容器:

container.RegisterType<IQuestionnaireViewModel, QuestionnaireViewModel>();

所以现在当你解决你的观点时,Unity会查找它应该用作实现的类 IQuestionnaireViewModel,看到它 QuestionnaireViewModel 并使用它。

回答问题2

正在使用Unity,因为为了使构造函数获取其参数,您需要使用容器来解析视图。如果您自己使用实例化视图,则不使用Unity new QuestionnaireView(),即不会发生构造函数或属性注入。

回答问题3

我认为这主要取决于什么更舒适以及需要使用注射成员的地方。很多时候,您只想在构造函数中设置局部变量,而不是仅为执行注入创建属性。

关于物业注入的一个好处是,你可以使用 container.BuildUp() 通过使用创建的实例的方法 new 而不是 container.Resolve<>()。这样,即使在创建之后,您也可以将成员注入属性 - 这是构造函数注入无法做到的事情。


13
2017-12-23 15:55



很棒的答案,干杯。 - Jim_CS
你说QuestionnaireViewModel是一个具体的类,所以不使用依赖注入。我现在明白你使用接口而不是具体类,所以你可以切换到不同的视图模型。能够使用不同的视图模型有什么用?这是否只有在开发应用程序而不是一个人的团队时才有用? - Jim_CS
@JohnMcDonald依赖注入可以用于viewmodel以外的许多东西。在具体类上使用接口使您能够轻松切换代码中的依赖项。例如,今天你可以使用 Log4NetLogger 做你的日志,但明天你想用 EnterpriseLibraryLogger。如果你用过 ILogger 对于注射,您需要做的就是更改将记录器注册到容器的行。如果还没有,则必须更改并重新编译使用记录器的每个类。 - Adi Lester