模型更改时刷新ViewModel的所有属性的数据绑定的好方法

时间:2011-01-10 21:00:54

标签: wpf data-binding mvvm inotifypropertychanged

短版

如果我更新了我的ViewModel包装的Model对象,那么为我的ViewModel公开的所有模型属性触发属性更改通知的方法是什么?

详细版本

我正在开发遵循MVVM模式的WPF客户端,并且我正在尝试处理从服务到我的视图中显示的数据的传入更新。当客户端收到更新时,更新以DTO的形式出现,我将其用作模型。

如果此模型是对View中显示的现有模型的更新,我希望关联的ViewModel更新其数据绑定属性,以便View反映更改。

让我举一个例子来说明。 考虑我的模型:

class FooModel
{
  public int FooModelProperty { get; set; }
}

包含在ViewModel中:

class FooViewModel
{
  private FooModel _model;

  public FooModel Model 
  { 
    get { return _model; }
    set 
    { 
      _model = value; 
      OnPropertyChanged("Model"); 
    }
  }

  public int FooViewModelProperty
  {
    get { return Model.FooModelProperty; }
    set 
    {
      Model.FooModelProperty = value;
      OnPropertyChanged("FooViewModelProperty");
    }    
}

问题:

当更新的模型到达时,我设置了ViewModel的Model属性,如下所示:

instanceOfFooVM.Model = newModel;

这会导致OnPropertyChanged("Model")触发,但不会OnPropertyChanged("FooViewModelProperty"),除非我从Model的setter明确调用后者。因此,当我更改模型时,绑定到FooViewModelProperty的视图将不会更新以显示该属性的新值。

明确地为每个公开的Model属性调用OnPropertyChanged显然不是一个理想的解决方案,也没有采用newModel并迭代其属性来逐个更新ViewModel的属性。

更新整个模型并需要为其所有公开属性发出更改通知的问题有什么更好的方法?

4 个答案:

答案 0 :(得分:57)

根据docs

  

PropertyChanged事件可以通过使用null或String.Empty作为PropertyChangedEventArgs中的属性名来指示对象上的所有属性都已更改。

答案 1 :(得分:7)

一种选择是收听您自己的事件,并根据需要制作一个帮助例程来提升其他通知。

这可以像在构造函数中添加一样简单:

public FooViewModel()
{
    this.PropertyChanged += (o,e) =>
      {
          if (e.PropertyName == "Model")
          {
               OnPropertyChanged("FooViewModelProperty");
               // Add other properties "dependent" on Model here...
          }
      };
}

答案 2 :(得分:1)

每当设置Model属性时,请订阅自己的PropertyChanged事件。当你的处理程序被调用时,启动你自己的PropertyChanged事件。将Model设置为其他内容时,请从旧版Model中删除处理程序。

示例:

class FooViewModel
{
    private FooModel _model;

    public FooModel Model 
    { 
        get { return _model; }
        set 
        { 
            if (_model != null)
            {
                _model.PropertyChanged -= ModelPropertyChanged;
            }

            if (value != null)
            {
                value.PropertyChanged += ModelPropertyChanged;
            }

            _model = value; 
            OnPropertyChanged("Model"); 
        }
    }

    public int FooViewModelProperty
    {
        get { return Model.FooModelProperty; }
        set 
        {
            Model.FooModelProperty = value;
            OnPropertyChanged("FooViewModelProperty");
        } 
    }

    private void ModelPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        // Here you will need to translate the property names from those
        // present on your Model to those present on your ViewModel.
        // For example:
        OnPropertyChanged(e.PropertyName.Replace("FooModel", "FooViewModel"));
    }
}

答案 3 :(得分:0)

    Implements INotifyPropertyChanged
    Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged 

    RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(String.Empty))

对于VB.net,如果有其他人需要它。如果您已经实施了" INotifyPropertyChanged"那么最后一行就是你所需要的。