我试图理解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更好的抽象,但我当然不会肯定的。 有人可以向我解释我错过了什么吗?感谢。
答案 0 :(得分:3)
在很多情况下,视图模型确实是通过看起来像额外的代码层来开始生活的,这些代码层并没有真正添加任何有价值的东西,但重点是它们可以进化。
VM的作用是为视图提供便利 - INotifyPropertyChanged
就是这样一种便利,而模型的作用是封装您的业务逻辑。随着代码功能的增长,意志越来越丰富;在某些时候,它的代码大小甚至可能比模型大得多。因此,区别在于方便性和业务逻辑部分保持良好的分离,这对代码的可维护性有很好的影响。
这里的原因是不同的:如果你这样做,然后需要将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,那么很难让它成为通知。