【问题标题】:MVVM and DI - How to handle Model objects?MVVM 和 DI - 如何处理模型对象?
【发布时间】:2010-07-27 15:34:52
【问题描述】:

我正在使用 Caliburn 和 C#,但我觉得这是一个通用的 MVVM/DI 问题。

假设我有一个视图模型 NoteViewModel,它传递了一个名为 Note 的模型对象。

这里有一些代码:

class NoteViewModel : PropertyChangedBase
{
  private readonly Note _note;

  public NoteViewModel(Note note)
  {
    _note = note;
  }

  public string Title
  { 
    get { return _note.Title; } 
    set { _note.Title = value; NotifyOfPropertyChange(() => Title); }
  }
}

现在这个对象是通过调用 new() 并传递一个模型对象来创建的。

嗯,这很好用,但现在我需要添加一个方法,该方法需要从我的 DI 容器中导入的类。

所以我只是调用 ServiceLocator.Current.GetInstance() 来获取它吗?或者我应该设计这个视图模型以通过 DI 容器创建并以某种方式设置传递 Note 对象的方法?

设计此视图模型的正确方法是什么?基本上是一个“PerInstance”视图模型,它需要一个模型对象才能使用。 Caliburn 是否有内置方法来执行此操作?

【问题讨论】:

  • 我想明确一点,我认为调用 ServiceLocator.Current 对我来说似乎 bad,事实上我有一个视图模型是通过调用 new() 而不是从我的 DI 容器中。

标签: c# .net wpf mvvm caliburn


【解决方案1】:

Caliburn 有一个接口(IHaveSubject 及其类型化版本 IHaveSubject)来解决这种情况:基本上,它允许在实例化后使用“主题”配置 ViewModel,通常是通过容器:

class NoteViewModel : PropertyChangedBase, IHasSubject<Note> {
  ...   
} 

myNoteViewModel = ... //obtain an instance
myNoteViewModel.WithSubject(new Note());

此解决方案还与 ISubjectSpecification / Conductor 很好地集成 基础设施。

尽管构造后初始化是一种简单有效的解决方案,但您可能不希望(从纯粹的设计角度)放弃显式构造函数参数来强制需要注释来实例化 ViewModel。 在这种情况下,我认为您必须利用 DI 容器的特殊功能,因为您可能有一些构造函数的参数表示“真实”输入参数,而其他可能是服务依赖项。

例如,Castle Windsor 有一个很好的功能,允许您快速为 ViewModel 构建显式(类型化)工厂;工厂方法只允许设置“真实”参数,而所有依赖项都由容器管理(有关此 Windsor 功能的详细描述,请参阅这篇文章:http://kozmic.pl/archive/2009/12/24/castle-typed-factory-facility-reborn.aspx

【讨论】:

  • 我正在使用带有 WPF 的 Caliburn 的全新 svn checkout。我发现Screen有这个功能,但是找不到IHasSubject,接口名称改了吗?
  • 实际上是 IHaveSubject。它位于 Caliburn.PresentationFramework.Screens 命名空间中。
  • IHaveSubject 到目前为止对我有用。关于何时必须传递 2 个模型对象的任何建议?在这种情况下升级到温莎城堡?我正在开展一个对模型几乎没有控制权的项目,我敢打赌这会发生。
  • 在我看来,这似乎是一个设计/建模问题:如果您想强制针对构建阶段指定的一个或多个模型创建 VM,则应该使用工厂模式。这是非常优雅和透露意图的;它还可以避免您忘记调用初始化方法。我相信大多数现有的 DI 容器都可以实现类似的设计;如果您选择 Windsor(我强烈推荐),您可以查看 Krzysztof 指出的示例应用程序。
  • 另一方面,您可以保留当前设计,创建您想要设置为主题的模型的组合;复合模型将包含对您需要传递给 VM 的任何模型的引用。这将更好地模拟 VM 的主题在其生命周期内打算更改的场景。
【解决方案2】:

你能用分层视图模型解决它吗?

对我来说越来越清楚的是,在构建更大的应用程序时,每个视图需要一个 ViewModel每个模型项或集合一个 ViewModel。

这样我们可以分层构建 ViewModel,匹配 XAML 层次结构。

然后可以通过应用程序的主视图模型在顶层定义或注入所需的对象。然后,嵌套视图模型可以按照您设计的方式访问任何内容,以使它们可以访问。

关于 Caliburn,我不知道有关该框架的任何具体情况,抱歉。

【讨论】:

    【解决方案3】:

    我也在使用 ServiceLocator。而且我这样做也“感到肮脏”。但是我已经决定使用 YAGNI 原则并保持这种模式,直到我发现在我的构造函数中添加 5 个 IService 的复杂性,通过 3-4 层继承将它们传递给需要它们的基类,并通过容器创建一切。当然,我的应用程序在不断发展,而 YAGNI 并不总是能持续...

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-06-14
      • 1970-01-01
      • 1970-01-01
      • 2010-12-06
      • 1970-01-01
      • 2011-11-14
      • 2013-03-03
      • 2012-02-03
      相关资源
      最近更新 更多