拥有Rich Models时你会怎么做?

时间:2011-10-06 13:30:53

标签: c# design-patterns mvvm viewmodel models

我正在使用一个项目中的现有代码,该项目遍布各处(而不是POCO)。基本上,有没有什么好方法可以混合丰富的模型和ViewModel而不重复代码?


  • 丰富的模型具有数据验证功能。使用ViewModels重用这些的简单方法吗?

示例:

public class PersonViewModel : INotifyPropertyChanged, IDataErrorInfo
{
    private Person _person;

    [Required] //This seems redundent...
    public String FirstName { ... }
}

public class Person
{
    [Required]
    public String FirstName { ... }
}

这只是一个例子......基本上,如果你有一个Rich Model,有什么方法可以利用它来维护MVVM并避免重复代码?我真的想避免让我的模型成为任何数据上下文或ViewModel完全公开。

例如:

public class PersonViewModel : INotifyPropertyChanged, IDataErrorInfo
{
    private Person _person;

    //This seems like a bad thing to do...
    public Person ThePerson { get { return _person; } }
}

3 个答案:

答案 0 :(得分:3)

这是一个经典问题。

如果您使用特定于表示层的接口和属性“污染”您的Model类,您只需拥有一个版本的任何逻辑模型即可获得效率,但却无法使表示和业务模型独立发展。

如果你保持你的模型“纯粹”并保持一个单独的视图模型,你可以获得灵活性,但由于必须维护(和映射)两个版本而失去效率。

从理论的角度来看,对于更复杂的系统,我会推荐后者。如果您的系统相对简单(想想CRUD)并且您不希望这两种类型的模型独立发展,那么前者可能非常安全。

显然,这两种方法并不相互排斥,并且在屏幕基础上做出决定并非闻所未闻。

答案 1 :(得分:1)

MVVM的一个想法是将表示层与数据层分开。这使您能够在不更改数据层数据的情况下更改表示层正在使用的数据。

因此,表示层中的数据仅在用户请求时写入您的数据层。您的冗余FirstName属性用作图层边框,使您可以灵活地实现类似简单的“撤消所有更改”。

考虑使用通用的ValueViewModel来处理数据绑定所需的值更改通知。按照这种方法,您的视图模型将类似于:

public class PersonViewModel : INotifyPropertyChanged, IDataErrorInfo
{
    private Person _person;

    [Required] //This seems redundent...
    public ValueViewModel<String> FirstName { ... }
}

使用此模式,您的模型不需要实现INotifyPropertyChanged接口,再次将表示层与数据层分开。

MVVM是一个非常顶级的模式,你经常会看到第一个视图看起来有些正式,但遵循这个模式会给你很大的灵活性。如果您选择违反MVVM规则,则会将整个应用程序架构纹理置于危险之中,因为这一违规会破坏您使用mvvm获得的灵活性。因此,如果您打算违反MVVM,请考虑根本不使用它。

答案 2 :(得分:1)

我从来没有看到从ViewModel为View公开整个模型的任何问题。我知道这不是“MVVM-Purist”方法,但它简单,快速,而且效果很好。

但我确实理解这两种方法同样有效,并且通常对于非常大的代码库,从长远来看,Model和ViewModel之间的分离使生活更轻松。在这种情况下,为什么不让ViewModel验证返回ModelValidation?它不像使用DataAnnotations那样漂亮,但你不会在多个位置创建验证。

例如,我经常使用这样的东西:

public string GetValidationError(string propertyName)
{
    string s = null;

    switch (propertyName)
    {
        case "FirstName":
        case "LastName":
            s = Person.GetValidationError(propertyName);
            break;
    }

    return s;
}

string IDataErrorInfo.this[string propertyName]
{
    get { return this.GetValidationError(propertyName); }
}