MVVM使用INotifyPropertyChanged模型而不通知ViewModel

时间:2011-09-14 19:03:28

标签: c# silverlight windows-phone-7 mvvm windows-phone-7.1

我第一次尝试使用MVVM。我有一个Windows Phone应用程序(Mango),它有一个模型类,一个视图模型类和一个视图xaml页面。我有控制(文本框)绑定到VM,并且VM绑定到模型。

模型和视图模型都实现了INotifyPropertyChanged。我正在使用的实现被复制,以便我可以使用它来试图找出我正在使用INPC做什么。以下是两个类中列出的代码:

public event PropertyChangedEventHandler PropertyChanged;

private void NotifyPropertyChanged(String info)
{
   if (PropertyChanged != null)
   {
      PropertyChanged(this, new PropertyChangedEventArgs(info));
   }
}

我在Model类中有一个属性,可以手动(从文本框)设置或计算(通过更改其他属性之一)。我们称之为一个结果。

如果我更改其他属性之一并逐步执行,则在模型类中的已更改属性和重新计算属性中都会调用INPC,尽管PropertyChangednull,因此代码被跳过。然后在VM中,已更改的属性逐步执行该类'INPC(作为set访问器的一部分),而这次PropertyChanged不是null,因此PropertyChanged方法是调用。但是,对于Result属性,不会引发INPC(该属性没有由其他属性的set访问器调用的INPC)。

以下是Model中的一个属性,它不是计算属性:

public int AgeSetting
{
   get
   {
      return (int)GetValueOrDefault(AgeSettingKeyName, AgeSettingDefault);
   }
   set
   {
      AddOrUpdateValue(AgeSettingKeyName, value);
      Calculate();
   }
}

以下是模型中计算值的属性。

public int PointsSetting
{
   get
   {
      return (int)GetValueOrDefault(PointsSettingKeyName, PointsSettingDefault);
   }
   set
   {
      AddOrUpdateValue(PointsSettingKeyName, value);
   }
}

从ViewModel,这里有两个属性:

public int Age
{
   get
   {
      return person.AgeSetting;
   }
   set
   {
      person.AgeSetting = value;
      NotifyPropertyChanged("Age");
   }
} 

public int PointsAllowed
{
   get
   {
      return person.PointsSetting;
   }
   set
   {
      person.PointsSetting = value;
      NotifyPropertyChanged("PointsAllowed");
   }
}

之前从未这样做过,我期待INPC应该从模型类,VM类和UI中冒出来。它似乎没有那样工作。

我知道Result(计算)属性正在改变,因为我可以离开页面并返回,并且新显示的值是正确的。我只是不知道如何从模型中的计算值,到视图模型,直到视图。

感谢您提出任何建议。

4 个答案:

答案 0 :(得分:5)

如果计算属性的值发生更改,则还会引发该属性的PropertyChanged事件。这意味着当单个属性发生更改时,可能会为多个属性触发事件。

此外,如果您的设计中可能/智能,您可以直接绑定到模型属性并使Model成为ViewModel的属性。这大大减少了代码维护。

答案 1 :(得分:3)

对于依赖于其他属性值的属性,程序员可以通知多个属性已更改。

给定一个具有三个属性的类 - Score,Multiplier和Total - 其中Total取决于Score和Multiplier的值,我可以像这样编写类:

public class ViewModel
{
    private int score;
    public int Score
    {
        get
        {
            return this.score;
        }
        set
        {
            if (this.score != value)
            {
                this.score = value;
                // Notify that this property has changed
                NotifyOfPropertyChange(() => this.Score);
                // Notify that a dependant property has changed
                NotifyOfPropertyChange(() => this.Total);
            }
        }
    }

    private int multiplier;
    public int Multiplier
    {
        get
        {
            return this.multiplier;
        }
        set
        {
            if (this.multiplier != value)
            {
                this.multiplier = value;
                // Notify that this property has changed
                NotifyOfPropertyChange(() => this.Multiplier);
                // Notify that a dependant property has changed
                NotifyOfPropertyChange(() => this.Total);
            }
        }
    }

    public int Total
    {
        get
        {
            return this.Score * this.Multiplier;
        }
    }
}

例如,您会注意到,当我设置Score的值时,我会通知Score和Total都已更改。你对NotifyOfPropertyChange的具体启示与我的不同,但中心思想是一样的。因为Total是依赖于其他属性值的属性,所以它永远不会通知。相反,Total所依赖的属性负责通知。

答案 2 :(得分:1)

在模型中,在计算属性的setter中调用NotifyPropertyChanged方法。您应用中的某些逻辑应该是更新模型。确保ViewModel订阅了此事件。这非常重要,因为我认为这正是你在这里所缺少的。

然后,在ViewModel中的EventHandler中,订阅了一个Model on PropertyChanged事件,更改ViewModel的相应属性值(此处视图模型中的方法更新视图模型中的属性),UI被绑定至。

答案 3 :(得分:1)

听起来您还没有在模型类上实现INotifyPropertyChanged接口。如果没有这个,你的事件处理程序在被调用时将为null。

public class ViewModel : INotifyPropertyChanged
{
   // Stuff
}

public class Model : INotifyPropertyChanged
{
   // Stuff
}

另请查看我的博客,了解一些MVVM的内容。我有一些教程以及一些在不使用字符串值的情况下触发Inotify的方法(使用反射代替)。