关于是否应该在模型中实现INotifyPropertyChanged
似乎存在矛盾的想法。我认为它应该在ViewModel中实现,但我无法弄清楚它是如何实现的。在stackoverlow.com(In MVVM model should the model implement INotifyPropertyChanged interface?,In MVVM should the ViewModel or Model implement INotifyPropertyChanged?)上有很多提及同样的想法,但我找不到任何示例来说明如何做到这一点。
比方说,我有一个模型Person:
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 ”的人如何得到模型变化的通知?
答案 0 :(得分:2)
ViewModel绝对应该实现INotifyPropertyChanged。我对是否应该在模型中实施它没有强烈的意见。当模型属性在绑定到View时不会独立于ViewModel进行更改时,我认为您不需要它。
无论如何,这是我在ViewModel中实现INotifyPropertyChanged时尚未在模型中实现的方式:
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(或类似的自定义通知事件)的情况下添加它,你无法获得有关模型中发生的变化的通知,而不是视图模型。我猜你应该能够避免这种情况。否则只需在其中实现INotifyPropertyChanged。如果你需要,那没有什么不妥。
答案 1 :(得分:1)
有趣的问题。我已经阅读了一年多的MVVM,我仍然不确定。
如果您的应用程序表示某个进程的状态,并且该状态在内部进行了修改而没有用户的任何交互,那么您的模型需要能够通知您的viewmodel它已更改。 因此,如果您的模型实现了INotifyPropertyChanged,并且您的viewmodel只将相同的信息传递给视图,那么......您的viewmodel是否确实需要存在...?
在我们公司,我们考虑两个主要案例:
我们在开发之前使用非常严格的UML分析来构建我们的软件(不那么敏捷)。当我们想要在屏幕上显示我们的对象时,它们会返回不同的视图,这些视图在需要时使用Bindings(使用ContentControl等)。我们软件所需的大多数视图都显示了这些实现INotifyPropertyChanged的对象,因此也是ViewModel的一种。
要构建软件主视图(视图结构),我们为它们创建全局视图和ViewModel。那是我们真正遵循MVVM实践的时候。
也许我错过了一个关于MVVM的观点,但根据我的经验,这并不是你必须始终遵循的模式。这是开发WPF应用程序的一种非常好的思维方式,但是对于每个视图创建ViewModel在我看来都是一个很大的开销。
你们怎么看待这种做法?
致以最诚挚的问候,
安托
编辑31.03.2012
我找到了一篇非常有趣的文章,解释了如何在viewmodel中处理模型属性,而不必在viewModel中为每个属性实现代理属性。 作者还说了一些关于在模型中实现INPC以及视图模型监听它的说法。 我认为这是迄今为止我读过的关于MVVM的最实用的文章。 看看这个 : http://msdn.microsoft.com/en-us/magazine/ff798279.aspx
答案 2 :(得分:0)
根据我的经验,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) )。
答案 3 :(得分:0)
除了错字之外,你几乎拥有它;)
您需要添加的是构造函数和属性定义:
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
,因为您不必担心将模型转换为ViewModel并返回。
但如果你不能,请参见上文:)