Person
クラス、PersonViewModel
およびPersonView
があるとします。
プロパティをPersonView
からPerson
モデルに更新するのは簡単です。 PersonViewModel
にはPerson
オブジェクトが含まれ、Personモデルを更新するためにPersonView
がバインドするパブリックプロパティがあります。
しかしながら。
Person
モデルがService
によって更新されることを想像してください。次に、プロパティの変更をPersonViewModel
に伝達し、次にPersonView
に伝達する必要があります。
これは私がそれを修正する方法です:
Person
モデルの各プロパティについて、PropertyChangedイベントを発生させます。 PersonViewModel
はPerson
のPropertyChangedイベントをサブスクライブします。次に、PersonViewModel
は、PersonView
を更新するために別のPropertyChangedを発生させます。
これは私には最も明白な方法のようですが、誰かが私にもっと良い方法を見せてくれることを期待して、この質問を投げ捨てたいと思います。本当にこれは単純ですか、それともモデルを変更済みとしてマークし、ViewModelのそれぞれのプロパティを更新するより良い方法がありますか?
PersonView
のDataContextはPersonViewModel
です。 Person
はJSONから読み込まれ、その存続期間中に何度も更新されます。
私の特定のケースについて、アーキテクチャの変更を自由に提案してください。
Aqwertは、既に提案したソリューションの代替手段を提供するため、質問の回答としてマークしました。
ビューがモデルに直接バインドされている場合、サービスが同じインスタンスを使用している限り、モデルプロパティへの変更はビューに反映されます。
ただし、サービスで新しいモデルを再作成する場合は、viewmodelに新しいモデルを指定します。モデルはビューモデルのプロパティとして表示されるので、そのプロパティを設定すると、すべてのバインディングに変更が通知されます。
//in the ViewModel
public Person Model
{
get { return _person; }
set { _person = value;
RaisePropertyChanged("Model"); //<- this should tell the view to update
}
}
編集:
特定のViewModel
ロジックがあると述べたので、ViewModel
でそれらのプロパティを調整できます
private void Model_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if(e.PropertyName == "Prop1") RaisePropertyChanged("SpecicalProperty");
...
}
public string SpecicalProperty
{
get
{
reutrn Model.Prop1 + " some additional logic for the view";
}
}
XAML
<TextBlock Text="{Binding Model.PropertyDirect}" />
<TextBlock Text="{Binding SpecicalProperty}" />
この方法では、Model
プロパティとViewModel
プロパティの両方のみが、データを複製せずにビューにバインドされます。
プロパティの変更をモデルからビューモデルにリンクするヘルパーを作成したり、マッピングディクショナリを使用したりできます。
_mapping.Add("Prop1", new string[] { "SpecicalProperty", "SpecicalProperty2" });
プロパティのリストを取得して、更新するプロパティを見つけます
private void Model_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
string[] props;
if(_mapping.TryGetValue(e.PropertyName, out props))
{
foreach(var prop in props)
RaisePropertyChanged(prop);
}
}
ビューがモデルに直接バインドする場合(ViewModelがモデルを公開する場合も同様)、UIコードとデータコードを混在させます。 MVVMの目標は、これら2つのコードドメインを分離することです。それがViewModelの目的です。
ビューモデルには、ビューがバインドできる独自のプロパティが必要です。例:
_class PersonViewModel
{
private Person OriginalModel { get; set; }
public ValueViewModel<string> Name { get; set; }
public ValueViewModel<int> Postcode { get; set; }
protected void ReadFromModel(Person person)
{
OriginalModel = person;
Name.Value = OriginalModel.Name;
Postcode.Value = OriginalModel.Postcode;
}
protected Person WriteToModel()
{
OriginalModel.Name = Name.Value; //...
return OriginalModel;
}
}
_
このようなViewModelデザインを使用すると、データオブジェクトがユーザーインターフェイスコードから実際に分離されます。クラスPersonの構造が変更された場合、ViewModelがお互いを分離するため、UIはそれに応じてフィットする必要はありません。
さてあなたの質問に。上記の例でわかるように、汎用の_ValueViewModel<T>
_を使用しました。このクラスはINotifyPropertyChanged
(および他のいくつかのもの)を実装します。新しいPerson
インスタンスを受け取ったら、ViewModelでReadFromModel(newPerson)
を呼び出すだけでUIが更新されます。これは、ViewがバインドするValueViewModelが値が変更されたときにUIに通知するためです。
以下は、ValueViewModel
の内部構造の非常に簡略化された例です。
_class ValueViewModel<T> : INotifyPropertyChanged
{
private T _value;
public T Value
{
get { return _value;}
set
{
_value = value;
RaisePropertyChanged("Value");
}
}
}
_
これは、MVVMライブラリで使用したアプローチです。これには、開発者がコードを設計者の懸念から明確に分離する必要があるという利点があります。また、副作用として、すべてのビューとビューモデルに標準化されたコードレイアウトを生成し、コードの品質を向上させます。