如何正确定义Model到ViewModel的关系?

时间:2012-05-11 11:34:54

标签: c# wpf architecture mvvm

我试图理解Model到ViewModel的关系,并且我一直在遇到同样的问题。 假设我们有一个只有一个字段的“Person”类:

public class Person
{
   public string Name;
}

在下一阶段,我让我的XAML艺术家创建了一个呈现Person的用户控件,并且他根据MVVM的实践需要将他的视图与VMPerson(View-Model Person)联系起来,所以现在我添加另一个类:< / p>

public class VMPerson : INotifyPropertyChange
{
   private Person person;

   public VMPerson():this(new Person()){}

   public VMPerson(Person person)
   {
      this.person = person;
   }

   public Name
   { get { return person.name; }
   { set { person.name = value; PropertyChange("Name"); }
}

所以现在我几乎所有的设置......但是我的VM类如何与我的模型类中的更改相关?如果我添加INotifyPropertyChanged并在模型中为“Name”添加一个属性,我将使用与我的ViewModel类非常相似的内容添加一个我不需要的额外层。有没有办法保持我的Model类不变,并且仍然会在视图模型类中通知它内部的更改?如果没有其他方法比使用INotifyPropertyChanged机制或任何类似的将在模型中实现的为什么我需要VM?是仅仅是为了将一些“模型”类聚合成一个将被提供给View的类?

我认为我必须在我的理解中遗漏一些东西因为在我看来,根据我所描述的模型来查看模式,而使用View代码隐藏作为控制器将比MVVM更好的抽象,但我当然不会肯定的。 有人可以向我解释我错过了什么吗?感谢。

3 个答案:

答案 0 :(得分:3)

将viewmodel代码放入模型中并不是最好的想法

在很多情况下,视图模型确实是通过看起来像额外的代码层来开始生活的,这些代码层并没有真正添加任何有价值的东西,但重点是它们可以进化

VM的作用是为视图提供便利 - INotifyPropertyChanged就是这样一种便利,而模型的作用是封装您的业务逻辑。随着代码功能的增长,意志越来越丰富;在某些时候,它的代码大小甚至可能比模型大得多。因此,区别在于方便性和业务逻辑部分保持良好的分离,这对代码的可维护性有很好的影响。

将viewmodel代码放入视图中不是最好的主意

这里的原因是不同的:如果你这样做,然后需要将viewmodel与另一种类型的视图一起使用,你将不得不将所有逻辑复制到另一个视图的代码隐藏中。复制很糟糕;干很好。

考虑到MVVM的一个非常重要的特性是它提供了可测试性,并且可测试性必然意味着至少两种类型的视图(真实的和模拟的),这种方法的必要性变得明显。

答案 1 :(得分:1)

viewmodel的一个目的是从模型中获取数据,以必须可视化数据的方式处理它。

例如,在您的模型中,您可以获得DateOfBirth信息,并且您希望可视化实际年龄。

在这种情况下,您应该在ViewModel中进行处理(将DateOfBirth转换为实际年龄,如DateTime.Now.Year - DateOfBirth.Year)。

在您的特定情况下,ViewModel只是模型中数据的包装器(无处理),并且显然不需要Viewmodel。

为了在ViewModel中获取模型更改(对于不需要在VM中处理的属性),我通常也在模型中实现INotifyPropertyChanged。这避免了ViewModel中的大量包装器属性。

在我的ViewModel中,我会有一些想法

_model.PropertyChanged += PropertyChangedEventHandler(OnPropertyChangedModel);

void OnPropertyChangedModel(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
    OnPropertyChanged(e.PropertyName);
}

请注意,在这种情况下,模型属性会直接发送到View(ViewModel中没有处理)。

答案 2 :(得分:1)

我看待它的方式如下: - ViewModel,这就像旧MVP中的Presenter一样,它将包含&amp;加入各种业务功能(如消耗IDealService和IStaticDataService)。

我的模型非常接近DataModel,它只是重复数据。

如果VM有太多与数据相关的位,我通常会将它们移动到Model中并使用VM中的实例。

即。你可以:

public class VMPerson : INotifyPropertyChange
{
   public Person PersonItem {get; set;}

   public VMPerson()
   {
      PersonItem = new Person();
   }
}

你仍然可以在你的via中找到Person的名字: {Binding PersonItem.Name}

我同意如果你的origianl Person类没有继承INPC,那么很难让它成为通知。