ViewModelがラップするModelオブジェクトを更新する場合、ViewModelが公開するすべてのモデルのプロパティのプロパティ変更通知を起動するgood方法は何ですか?
私はMVVMパターンに従ってWPFクライアントを開発しており、サービスから、ビューに表示されているデータへの着信更新を処理しようとしています。クライアントが更新を受信すると、更新はモデルとして使用する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");
}
}
_
問題:
更新されたモデルが到着したら、ViewModelのModelプロパティを次のように設定します。
_instanceOfFooVM.Model = newModel;
_
これにより、Model
のセッターから後者を明示的に呼び出さない限り、OnPropertyChanged("Model")
は起動しますが、OnPropertyChanged("FooViewModelProperty")
は起動しません。したがって、FooViewModelProperty
にバインドされたビューは、モデルを変更しても更新されず、そのプロパティの新しい値が表示されません。
公開されたすべてのモデルプロパティに対してOnPropertyChanged
を明示的に呼び出すことは明らかに望ましい解決策ではありません。また、newModel
を取得してそのプロパティを反復処理し、ViewModelのプロパティを1つずつ更新することもできません。
モデル全体を更新し、公開されているすべてのプロパティに対して変更通知を発行する必要があるというこの問題に対するより良いアプローチは何ですか?
docs によると:
PropertyChangedイベントは、PropertyChangedEventArgsのプロパティ名としてnullまたはString.Emptyを使用して、オブジェクトのすべてのプロパティが変更されたことを示すことができます。
1つのオプションは、独自のイベントをリッスンし、必要に応じて他の通知を発生させるヘルパールーチンを作成することです。
これは、コンストラクタに追加するのと同じくらい簡単です。
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」をすでに実装している場合は、最後の行で十分です。