对于“模型”应该或不应该包含什么,我总是有点困惑 - 教程和示例经常互相矛盾。到目前为止,我一直在玩它安全,我的模型只露出“UI东西”,例如绑定到视图的属性,以及验证逻辑。但是在模型中有其他业务逻辑是否可以接受?
假设我想通过网络服务控制机械泵,该服务提供了以给定速度打开泵并再次关闭泵的方法。我的UI视图可能包含“on”& “关闭”按钮,加上一个文本框来设置速度。考虑到这一点,我的模型可能会这样开始: -
public class Pump
{
public int Speed { get; set; }
}
// The real thing would implement INotifyPropertyChanged, validation, etc.
这是所有模型应该做的,或者是否可以公开用于打开和关闭泵的业务逻辑 - 或者作为视图模型调用的方法,或者甚至可以作为可以直接绑定的ICommands到视图的按钮?或者所有这些都应该在视图模型中?
修改 我不认为为什么这是一个非常合理的问题。虽然网上有许多MVVM教程和示例,但它们往往提供相互矛盾的建议,就像下面提供的答案一样。我甚至最终阅读了WPF专家Josh Smith的“高级MVVM”电子书 - 这本书没有提到任何模型!
无论如何,我找到了一个很好的资源here给任何想要低估MVVM结构的人。虽然该链接将您带入Microsoft的Prism框架的文档,但这个特定的页面都是关于MVVM结构的,很少或没有Prism特定的。我发现这个页面非常有用,并且至少让我放心,确认我在过去几年里所做的事情是完全有效的 - 也就是说,拥有实现INPC和验证的模型(IDataErrorInfo) ,并通过VM属性将这些模型直接绑定到视图(而不是VM中的重复模型属性,如下面提到的一些答案)。
答案 0 :(得分:2)
模型的目的是模型您的域。实体,业务逻辑,服务 - 这都属于模型。与UI绑定的是视图模型。
在您的泵示例中,Pump
类不应实现INotifyPropertyChanged
以便在UI中使用它,因为它不应在UI中使用。这是视图模型的作用。更合适的设计将是
public class PumpService
{
public void Start() { ... };
public void Stop() { ... };
}
public class PumpControllerViewModel : INotifyPropertyChanged
{
public PumpControllerViewModel(PumpService service)
{
StartPump = new Command(() => service.Start());
// ...
}
public ICommand StartPump { get; private set; }
public ICommand StopPump { get; private set; }
}
在大多数情况下,模型对UI几乎不可见。视图模型经常暴露模型属性,但很少直接公开。如果您的应用程序需要显示泵速,则视图模型必须将其公开为可观察属性。
更新以回应OP问题
(...)如果我有一个包含许多属性的更复杂模型,例如一个客户? (...)您建议通过VM上的可观察属性公开每个模型属性 - 这是否涉及大量重复属性,映射代码等?
模型复杂性在这里是无关紧要的,是的,这种方法会引发一些代码重复(在某种程度上)。
如果您保持模型简单( DTO / POCO - 简单),那么您需要做的就是重写 POCO - 模型到 INPC - 查看模型。模型类只有很少的代码,而VM会处理到视图通知(关于它的角色)。
假设大多数复杂模型是通过工厂方法/构建器/服务创建的(例如,不是直接),那么视图模型也是如此。然后,您可以使用自动化程序,序列化程序或任何您需要的内容来简化复制过程。
你必须维护两个类似的类,但这是MVVM提供的清洁分离的有价值的权衡。
答案 1 :(得分:0)
嗯,实际上......你提到的“UI内容”应该放在ViewModels
中。 那些东西中的一些也可以在模型中,验证可以直接在视图中(加上绑定等)。
我建议您在第一部分阅读Prism 4.1开发人员指南(chapter 5)。
答案 2 :(得分:0)
But is it acceptable to have other business logic in a model?
是的,域名驱动的倡导者会鼓励这种设计。您的业务逻辑将在这里,但不是持久性逻辑。
Or should all this be in the view-model?
您可以将视图模型用作DTO - 仅在视图上显示属性的类。他们应该没有或只有很少的业务逻辑 - 这是许多开发人员犯的错误。您的视图将绑定到您的视图模型,视图模型将与您的模型交互,在其上设置属性并调用它包含的逻辑。
答案 3 :(得分:0)
有趣的是,在这种情况下,我倾向于使用WebService
作为Model
。
我认为您可能也会将Model
与ViewModel
混淆。通常情况下,特定于UI的内容肯定在ViewModel
上,让Model
清楚地完成实际工作。例如
View
- 有一个用于设置泵速的滑块,以及一些butttons,Fast,Slow,Stop。这些按钮将绑定到ViewModel
上的相关命令(这确实有助于测试),并且滑块绑定到Speed
的{{1}}属性。
ViewModel
MVVMLight的Laurent Buyginon创作者有一个非常好的例子,但我找不到它。它位于http://blog.galasoft.ch/posts/
的某个地方