当模型中的属性发生更改时得到通知
本文关键字:通知 模型 属性 | 更新日期: 2023-09-27 18:29:30
关于INotifyPropertyChanged
是否应该在模型中实现,似乎存在着相互矛盾的想法。我认为它应该在ViewModel中实现,但我不知道如何实现。stackoverlow.com上到处都提到了同样的想法(在MVVM模型中,模型是否应该实现INotifyPropertyChanged接口?在MVVM中,ViewModel或model是否应该实现INotifyPropertyChanged?),但我找不到任何例子来说明如何做到这一点。
举个例子,我有一个模型人物:
Public Person {
public int Age { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public void NameChange( string newName );
}
如何实现ViewModel,以便识别Age
、FirstName
或LastName
中的所有更改?
Public PersonViewModel : INotifyPropertyChanged {
Person _person;
public event PropertyChangedEventHandler PropertyChanged;
void OnPropertyChanged(string propertyName) {
if(this.PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
//ctor, Properties, etc...
}
编辑-澄清:
那么在不更改Person模型的情况下如何修改ViewModel以获得更新通知?
这可能吗?如果没有,订阅"模型中的INPC是baaaad"的用户如何获得模型更改的通知?
ViewModel肯定应该实现INotifyPropertyChanged。我对是否也应该在模型中实施它没有强烈的意见。当模型属性在绑定到视图时没有独立于ViewModel进行更改时,我认为您不需要它。
不管怎样,当INotifyPropertyChanged还没有在模型中实现时,我就是这样在ViewModel中实现的:
public class PersonViewModel : INotifyPropertyChanged
{
private Person person;
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
if(PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
public PersonViewModel(Person person)
{
this.person = person;
}
public int Age
{
get { return person.Age; }
set
{
if (value != person.Age)
{
person.Age = value;
OnPropertyChanged("Age");
}
}
}
public string FirstName
{
get { return person.FirstName; }
set
{
if (value != person.FirstName)
{
person.FirstName = value;
OnPropertyChanged("FirstName");
}
}
}
public string LastName
{
get { return person.LastName; }
set
{
if (value != person.LastName)
{
person.LastName = value;
OnPropertyChanged("LastName");
}
}
}
}
看到你是如何更新你的问题的,我需要补充一点,如果没有在模型中实现INotifyPropertyChanged(或类似的自定义通知事件),你就无法独立于ViewModel获得关于模型中发生的更改的通知。我想你应该能够避免这种情况。否则,只需在其中实现INotifyPropertyChanged。如果您需要它,这没有错。
有趣的问题。我已经读了一年多关于MVVM的书了,但我仍然不确定
例如,如果您的应用程序表示流程的状态,并且该状态在没有用户任何交互的情况下在内部进行了修改,那么您的模型需要能够通知您的视图模型它已更改。因此,如果你的模型实现了INotifyPropertyChanged,而你的视图模型只向视图传递相同的信息,那么。。。你的视图模型真的需要存在吗。。。?
在我们公司,我们考虑两种主要情况:
-
在开发之前,我们用非常严格的UML分析来构建我们的软件(不那么敏捷)。当我们想要在屏幕上显示对象时,它们会向我们返回它们不同的视图,这些视图在需要时与Bindings一起使用(使用ContentControl等)。我们的软件所需的大多数视图都显示了这些类型的对象,这些对象实现了INotifyPropertyChanged,因此也是ViewModels的一种。
-
为了构建软件主视图(视图结构),我们为它们创建全局视图和ViewModels。这就是我们真正遵循MVVM实践的时候。
也许我错过了关于MVVM的一点,但根据我的经验,这不是一个你必须始终遵循的模式。开发WPF应用程序是一种很好的思维方式,但为每个视图创建ViewModel对我来说似乎是一项巨大的开销。
你们都认为这种做法怎么样?
致问候,
Antoine
2012年3月31日版
我发现了一篇非常有趣的文章,解释了如何在viewmodel中处理模型属性,而不必在viewmodel中为每个属性实现代理属性。此外,作者还介绍了在模型中实现INPC的一些内容,以及视图模型对其的监听。我认为这是迄今为止我读过的关于MVVM的最实用的文章。看看:http://msdn.microsoft.com/en-us/magazine/ff798279.aspx
根据我的经验,Model
对象不必(也可能不应该)知道它们是在View
中构造的。通常,Model
对象是不应允许其处于无效状态的实体。ViewModel
对象是构成Model
对象的事物。
因此,由于您永远不想创建一个非常老或非常年轻的人,并且每个人都需要一个名字,因此您的Person
类可能看起来像这样:
public class Person {
public int Age { get; private set; }
public string Name { get; private set; }
public Person(int age, string name) {
if (age < 0 || age > 150) throw new ArgumentOutOfRangeException();
if (string.IsNullOrEmpty(name)) throw new ArgumentNullException();
Age = age;
Name = name;
}
}
你的PersonViewModel
可能看起来像这样::
class PersonViewModel : INotifyPropertyChanged {
private int _Age;
private int _Name;
public int Age {
get { return _Age; }
set {
if (_Age.Equals(value)) return;
_Age = value;
RaisePropertyChanged("Age");
}
}
public string Name {
get { return _Name; }
set {
if (_Name.Equals(value)) return;
_Name = value;
RaisePropertyChanged("Name");
}
}
public Person CreatePerson() {
return new Person(_Age, _Name);
}
}
然后,您可以在PersonViewModel
中放入所需的任何值,而无需担心创建无效的Person
对象。您还可以在PersonViewModel
中执行验证,该验证可能比Person
类中的验证更严格(例如,将年龄范围限制为18岁以上的成年人(请参阅IDataErrorInfo))。
省去你几乎有的打字错误;)
您只需要添加构造函数和属性定义:
public class PersonViewModel : INotifyPropertyChanged
{
Person _person;
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
{
var e = new PropertyChangedEventArgs(propertyName);
handler(this, e);
}
}
public PersonViewModel(Person person)
{
_person = person;
}
public int Age
{
get
{
return _person.Age;
}
set
{
_person.Age = value;
OnPropertyChanged("Age");
}
}
}
如果您有选择的话,我绝对建议您在模型中实现INotifyPropertyChanged
,因为您不必担心将模型转换为ViewModels并返回。
但如果不能,请参阅上面的内容:)