MVVM:ViewModel和业务逻辑连接

时间:2013-05-02 12:51:38

标签: c# wpf design-patterns mvvm

使用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通知,我会避免这种情况。 因此,业务和演示逻辑是分开的,但这使得很难通知用户界面。

4 个答案:

答案 0 :(得分:48)

将业务逻辑放在viewmodel中是一种非常糟糕的做事方式,因此我会快速说从不这样做并继续讨论第二种选择。

将逻辑放在模型中更合理,这是一个很好的启动方法。有什么缺点?你的问题是

  

因此,如果触发重命名模型以按方法操作某些数据   调用时,ViewModel没有线索操纵数据。因为   模型不包含任何PropertyChange通知,我会   避免这样做。

好吧,制作模型工具INotifyPropertyChanged肯定会让你继续前进到更好的事情。但是,有时候不可能这样做 - 例如,模型可能是一个部分类,其中属性由工具自动生成,不会引发更改通知。这是不幸的,但不是世界末日。

如果你想买东西,某人必须付钱;如果它不是提供此类通知的模型,那么您只剩下两个选择:

  1. viewmodel知道模型上的哪些操作(可能)导致更改,并在每次此类操作后更新其状态。
  2. 其他人知道哪些操作会导致更改,并且它们会在模型包装更改后通知viewmodel更新其状态。
  3. 第一个选项也是一个坏主意,因为实际上它将回到将“业务逻辑”放在视图模型中。没有像将所有业务逻辑放在viewmodel中一样糟糕,但仍然如此。

    第二种选择更有希望(不幸的是更多的工作要实施):

    • 将您的部分业务逻辑放在一个单独的类(“服务”)中。该服务将通过适当处理模型实例来实现您希望执行的所有业务操作。
    • 这意味着服务知道模型属性何时可能发生变化(这没关系:模型+服务==业务逻辑)。
    • 该服务将向所有相关方提供有关更改模型的通知;您的视图模型将依赖于服务并接收这些通知(因此他们将知道“他们的”模型何时更新)。
    • 由于业务操作也是由服务实现的,这仍然非常自然(例如,当在viewmodel上调用命令时,反应正在调用服务上的适当方法;请记住,viewmodel本身不知道业务逻辑)。

    有关此类实施的详细信息,请参阅我的答案herehere

答案 1 :(得分:12)

这两种方法都是有效的,但还有第三种方法:在模型和VM层之间实现服务。如果您想让模型保持愚蠢,服务可以提供与UI无关的中间人,可以以可重复使用的方式强制执行您的业务规则。

  

因为模型不包含任何PropertyChange通知,我将避免使用

你为什么要避免这个?不要误解我的意思,我倾向于让我的模型尽可能地保持愚蠢,但是在模型中实现更改通知有时会很有用,并且当你这样做时,你只会依赖于System.ComponentModel。它完全与UI无关。

答案 2 :(得分:1)

我做以下

  1. 仅使用XAML视图逻辑进行查看

  2. ViewModel,用于处理点击处理程序和创建新的视图模型。处理路由事件等。

  3. 模型,它是关于验证模型数据的数据容器和业务逻辑。

  4. 使用数据填充模型的服务。例如,调用Web服务器,从磁盘加载,保存到磁盘等。根据示例,我的模型和服务通常都会实现IPropertyChanged。或者他们可能会有事件处理程序。

  5. 任何复杂的应用程序都需要另一层。我称之为模型+服务,视图,视图模型。该服务抽象您的业务逻辑,并将模型实例作为依赖项或创建模型。

答案 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模式,我实际上正在使用它,将业务逻辑抽象到控制器类而不是模型或视图模型是很好的