4

我第一次尝试使用 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 会在 Model 类中的已更改属性和重新计算的属性中调用,尽管PropertyChangedis null,因此会跳过该部分代码。然后在 VM 中,被更改的属性会通过该类的 INPC(作为 set 访问器的一部分),而这次PropertyChanged不是null,因此PropertyChanged调用该方法。但是,对于该Result属性,不会引发 INPC(该属性没有由其他属性的 set 访问器调用的 INPC)。

这是模型中的属性之一,它不是计算的属性:

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 (calculated) 属性正在发生变化,因为我可以离开页面并返回,并且新显示的值是正确的。我只是不知道如何从模型中的计算值到视图模型,再到视图。

感谢您的任何建议。

4

4 回答 4

5

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

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

于 2011-09-14T19:11:40.823 回答
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 所依赖的属性负责通知。

于 2011-09-14T19:30:05.877 回答
1

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

然后,在 ViewModel 中的 EventHandler 中,即订阅了 Models on PropertyChanged 事件,更改 UI 绑定到的 ViewModel 的适当属性值(此处视图模型中的方法更新视图模型中的属性)。

于 2011-09-14T19:14:28.313 回答
1

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

public class ViewModel : INotifyPropertyChanged
{
   // Stuff
}

public class Model : INotifyPropertyChanged
{
   // Stuff
}

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

于 2011-09-14T23:42:47.727 回答