使用MVVM模式完成一些项目之后,我仍在努力使用ViewModel的角色:
我过去做过的事: 仅将模型用作数据容器。 使逻辑操纵ViewModel中的数据。 (那是商业逻辑吗?) Con:逻辑不可重用。
我现在正在尝试的事情: 保持ViewModel尽可能薄。 将所有逻辑移动到模型层。 仅在ViewModel中保留演示逻辑。 Con:如果在模型层内更改了数据,则会使UI通知真的很痛苦。
所以我会给你一个例子,让它更清晰:
方案: 重命名文件的工具。 类别: 文件:代表每个文件; 规则:包含逻辑如何重命名文件;
如果我遵循方法1: 为文件,规则和视图创建ViewModel - > RenamerViewModel。 将所有逻辑放在RenamerViewModel中: 包含FileViewModel和RuleViewModel的列表以及正在进行的逻辑。 简单快速,但不可重复使用。
如果我遵循方法2: 创建新的模型类 - >重命名器,包含文件列表,规则和进行逻辑以对每个文件进行交互并应用每个规则。 为文件,规则和重命名器创建视图模型。 现在RenamerViewModel只包含一个Renamer Model的实例,加上两个ObservableCollections来包装Renamer的File和Rule List。 但整个逻辑都在Renamer模型中。因此,如果触发重命名模型以通过方法调用操作某些数据,则ViewModel不知道哪些数据被操纵。 因为模型不包含任何PropertyChange通知,我会避免这种情况。 因此,业务和演示逻辑是分开的,但这使得很难通知用户界面。
答案 0 :(得分:48)
将业务逻辑放在viewmodel中是一种非常糟糕的做事方式,因此我会快速说从不这样做并继续讨论第二种选择。
将逻辑放在模型中更合理,这是一个很好的启动方法。有什么缺点?你的问题是
因此,如果触发重命名模型以按方法操作某些数据 调用时,ViewModel没有线索操纵数据。因为 模型不包含任何PropertyChange通知,我会 避免这样做。
好吧,制作模型工具INotifyPropertyChanged
肯定会让你继续前进到更好的事情。但是,有时候不可能这样做 - 例如,模型可能是一个部分类,其中属性由工具自动生成,不会引发更改通知。这是不幸的,但不是世界末日。
如果你想买东西,某人必须付钱;如果它不是提供此类通知的模型,那么您只剩下两个选择:
第一个选项也是一个坏主意,因为实际上它将回到将“业务逻辑”放在视图模型中。没有像将所有业务逻辑放在viewmodel中一样糟糕,但仍然如此。
第二种选择更有希望(不幸的是更多的工作要实施):
答案 1 :(得分:12)
这两种方法都是有效的,但还有第三种方法:在模型和VM层之间实现服务。如果您想让模型保持愚蠢,服务可以提供与UI无关的中间人,可以以可重复使用的方式强制执行您的业务规则。
因为模型不包含任何PropertyChange通知,我将避免使用
你为什么要避免这个?不要误解我的意思,我倾向于让我的模型尽可能地保持愚蠢,但是在模型中实现更改通知有时会很有用,并且当你这样做时,你只会依赖于System.ComponentModel
。它完全与UI无关。
答案 2 :(得分:1)
我做以下
仅使用XAML视图逻辑进行查看
ViewModel,用于处理点击处理程序和创建新的视图模型。处理路由事件等。
模型,它是关于验证模型数据的数据容器和业务逻辑。
使用数据填充模型的服务。例如,调用Web服务器,从磁盘加载,保存到磁盘等。根据示例,我的模型和服务通常都会实现IPropertyChanged。或者他们可能会有事件处理程序。
任何复杂的应用程序都需要另一层。我称之为模型+服务,视图,视图模型。该服务抽象您的业务逻辑,并将模型实例作为依赖项或创建模型。
答案 3 :(得分:0)
您还可以在Model和ViewModel上实现IDataErrorInfo,但仅在Model中进行验证,这将简化您在Model ...中实现业务规则的方式...
例如:
视图模型:
...
private Person person;
...
string IDataErrorInfo.this[string propertyName]
{
get
{
string error = (person as IDataErrorInfo)[propertyName];
return error;
}
}
型号:
public class Person:INotifyPropertyChanged,IDataErrorInfo
{
...
string IDataErrorInfo.this[string propertyName]
{
get { return this.GetValidationError(propertyName); }
}
...
string GetValidationError(string propertyName)
{
if(propertyName == "PersonName")
//do the validation here returning the string error
}
}
另外看一下MVCVM模式,我实际上正在使用它,将业务逻辑抽象到控制器类而不是模型或视图模型是很好的