Хороший способ обновить привязку данных для всех свойств ViewModel при изменении модели - PullRequest
30 голосов
/ 11 января 2011

Короткая версия

Если я обновлю объект Model, который оборачивает мой ViewModel, каков хороший способ запуска уведомлений об изменении свойств для всех свойств модели, которые предоставляет мой ViewModel?

Подробная версия

Я разрабатываю клиент WPF по шаблону MVVM и пытаюсь обрабатывать входящие обновления из службы в данные, отображаемые в моих представлениях.Когда клиент получает обновление, оно появляется в форме DTO, который я использую в качестве модели.

Если эта модель является обновлением существующей модели, отображаемой в представлении, я хочу, чтобы связанный ViewModel обновил свои свойства привязки к базе данных, чтобы представление отражало изменения.

Позвольте мне проиллюстрировать это примером. Рассмотрим мою модель:

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");
    }    
}

Проблема:

Когда прибывает обновленная модель, я устанавливаю свойство Model в ViewModel, например:

instanceOfFooVM.Model = newModel;

Это вызывает OnPropertyChanged("Model"), но не OnPropertyChanged("FooViewModelProperty"), если я не вызываю последнюю явно изModel сеттер.Таким образом, представление, привязанное к FooViewModelProperty, не будет обновляться для отображения нового значения этого свойства при изменении модели.

Явный вызов OnPropertyChanged для каждого открытого свойства модели, очевидно, не является желательным решением, и ни одно из них не являетсяберём newModel и перебираем его свойства, чтобы обновить свойства ViewModel по одному.

Как лучше подойти к этой проблеме обновления всей модели и необходимости запускать уведомления об изменениях для всех ее открытых свойств?

Ответы [ 4 ]

57 голосов
/ 11 января 2011

Согласно документам :

Событие PropertyChanged может указывать на то, что все свойства объекта были изменены с использованием значения null или String.Empty в качестве имени свойства в PropertyChangedEventArgs.

7 голосов
/ 11 января 2011

Одним из вариантов является прослушивание ваших собственных событий и создание вспомогательной процедуры для вызова других уведомлений по мере необходимости.

Это может быть просто добавление в конструкторе:

public FooViewModel()
{
    this.PropertyChanged += (o,e) =>
      {
          if (e.PropertyName == "Model")
          {
               OnPropertyChanged("FooViewModelProperty");
               // Add other properties "dependent" on Model here...
          }
      };
}
1 голос
/ 11 января 2011

Всякий раз, когда установлено свойство 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"));
    }
}
0 голосов
/ 04 ноября 2016
    Implements INotifyPropertyChanged
    Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged 

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

Для VB.net, если кому-то еще это нужно.Если вы уже внедрили INotifyPropertyChanged, тогда последняя строка - это все, что вам нужно.

...