当模型中的属性发生更改时得到通知

本文关键字:通知 模型 属性 | 更新日期: 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,以便识别AgeFirstNameLastName中的所有更改?

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并返回。

但如果不能,请参阅上面的内容:)