MVVM 和 DI - 如何处理模型对象?
我正在使用 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 有内置方法可以做到这一点吗?
I'm using Caliburn and C#, but I feel like this is a generic MVVM/DI question.
Let's say I have a view model, NoteViewModel, that is passed a model object called Note.
Here is some code:
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); }
}
}
Right now this object is created by calling new() and passing a model object.
Well, that works great, but now I need to add a method that requires an imported class from my DI container.
So do I merely call ServiceLocator.Current.GetInstance() to get it? Or should I design this view model to be created via the DI container and somehow setup a way to pass a Note object?
What is the proper way to design this view model? Basically a "PerInstance" view model that requires a model object for it's use. Does Caliburn have a built-in way to do this?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
Caliburn 有一个接口(IHaveSubject 及其类型化版本 IHaveSubject)来解决这种情况:基本上,它允许在实例化后使用“主题”配置 ViewModel,通常是通过容器:
该解决方案还与 ISubjectSpecification / Conductor 很好地集成
基础设施。
尽管构造后初始化是一个简单而有效的解决方案,但您可能不希望(从纯粹的设计角度来看)放弃显式构造函数参数来强制需要注释来实例化 ViewModel。
在这种情况下,我认为您必须利用 DI 容器的特殊功能,因为您可能有一些表示“真实”输入参数的构造函数参数,而其他参数可能是服务依赖项。
例如,Castle Windsor 有一个很好的功能,允许您快速为 ViewModel 构建显式(类型化)工厂;工厂方法只允许设置“真实”参数,而所有依赖项均由容器管理(有关此 Windsor 功能的详细描述,请参阅这篇文章:http://kozmic.pl/archive/2009/12/24/castle-typed-factory-facility-reborn .aspx)
Caliburn has an interface (IHaveSubject and its typed version IHaveSubject) addressing this kind of scenario: basically it allows a mean to configure the ViewModel with a "subject" after its instantiation, tipically through the container:
This solution also integrates well with ISubjectSpecification / Conductor
infrastructure.
Even though post-construction initialization is a simple and effective solution, you may not want (from a pure design perspective) to renounce to an explicit constructor parameter to enforce the need for a Note to istantiate the ViewModel.
In this case I think you have to leverage peculiar features of your DI container, because you may have some parameters of the constructor representing a "real" input parameter, while other may be service dependencies.
Castle Windsor, for example, has a nice feature allowing you to quickly build an explicit (typed) factory for your ViewModel; the factory method will only allow to set the "real" parameters, while all dependencies are managed by the container (see this post for an extensive description of this Windsor feature: http://kozmic.pl/archive/2009/12/24/castle-typed-factory-facility-reborn.aspx)
你能使用分层视图模型来解决这个问题吗?
对我来说,越来越清楚的是,在构建较大的应用程序时,每个视图需要一个 ViewModel,并且每个模型项或集合需要一个 ViewModel。
这样我们就可以分层构建 ViewModel,与 XAML 层次结构相匹配。
然后,所需的对象可以由应用程序的主视图模型在顶层定义或注入。然后,嵌套视图模型可以按照您设计的方式访问任何内容,以使它们可以访问任何内容。
关于 Caliburn,我不知道该框架的任何具体情况,抱歉。
Can you solve it using hierarchical view models?
To me it becomes more and more clear that I need one ViewModel per View and one ViewModel per model item or collection when building larger application.
That way we can build up ViewModels hierarchically, matching the XAML hierarchy.
The required objects can be defined or injected at the top level by app's main view model then. The nested view models can then access anything the way you design it to make things reachable by them.
About Caliburn, I don't know any specific things about that framework, sorry.
我也在使用 ServiceLocator。而且我这样做也“感觉肮脏”。但我决定使用 YAGNI 原则并保留这种模式,直到我发现向构造函数中添加 5 个 IService 的复杂性有令人信服的回报,通过 3-4 层继承将它们传递到需要它们的基类,并通过容器创建一切。当然,我的应用程序正在不断发展,而 YAGNI 并不总是能持续下去......
I'm using the ServiceLocator also. And I also "feel dirty" in doing this. But I have resolved to use the YAGNI principle and keep this pattern until I find a compelling payback to the complexity of adding 5 IServices into my constructors, passing them up via 3-4 layers of inheritance to the base classes in which they are needed, and creating everything via the container. Of course my app is evolving, and YAGNI doesn't always last...