Ответ 1
В соответствии с docs:
Событие PropertyChanged может указывать, что все свойства объекта были изменены с помощью null или String.Empty в качестве имени свойства в PropertyChangedEventArgs.
Если я обновляю объект 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 один за другим.
Какой лучший подход к этой проблеме обновления целой модели и необходимости запускать уведомления об изменениях для всех ее открытых свойств?
В соответствии с docs:
Событие PropertyChanged может указывать, что все свойства объекта были изменены с помощью null или String.Empty в качестве имени свойства в PropertyChangedEventArgs.
Один из вариантов - прослушивать свои собственные события и создавать вспомогательную подпрограмму, чтобы поднять другие уведомления по мере необходимости.
Это может быть так же просто, как добавить в свой конструктор:
public FooViewModel()
{
this.PropertyChanged += (o,e) =>
{
if (e.PropertyName == "Model")
{
OnPropertyChanged("FooViewModelProperty");
// Add other properties "dependent" on Model here...
}
};
}
Всякий раз, когда установлено свойство 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"));
}
}
Implements INotifyPropertyChanged
Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(String.Empty))
Для VB.net, если кому-то это нужно. Если вы уже внедрили "INotifyPropertyChanged", тогда вам понадобится последняя строка.