4

我正在使用 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 是否有内置方法来执行此操作?

4

3 回答 3

3

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 )

于 2010-07-27T16:58:33.477 回答
0

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

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

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

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

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

于 2010-07-27T16:13:20.240 回答
0

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

于 2010-07-27T19:31:58.800 回答