34

場合

Personクラス aとPersonViewModelaがあるとしPersonViewます。

PersonViewからモデルへのプロパティの更新Personは簡単です。PersonViewModelオブジェクトを含み、Person モデルを更新するためにバインドするPersonパブリック プロパティを持ちます。PersonView

でも。

Personモデルが によって更新されると想像してくださいServicePersonViewModelここで、プロパティの変更を に伝達し、次に に伝達する必要がありますPersonView

これは私がそれを修正する方法です:

モデルの各プロパティに対してPerson、PropertyChanged イベントを発生させます。PersonViewModelの PropertyChanged イベントをサブスクライブしPersonます。PersonViewModelを更新するために別の PropertyChanged を発生させPersonViewます。

これは私には最も明白な方法のように思えますが、誰かが私にもっと良い方法を示してくれることを期待して、この質問を投げかけたいと思います. 本当にこれは単純ですか、それともモデルを変更済みとしてマークし、ViewModel のそれぞれのプロパティを更新するより良い方法はありますか?

追加

PersonViewDataContext はPersonViewModel. PersonJSON から入力され、その有効期間中に何度も更新されます。

私の特定のケースのアーキテクチャの変更を自由に提案してください。

答え

aqwert は、私が既に提案したソリューションの代替案を提供してくれたため、質問の回答としてマークしました。

4

2 に答える 2

32

ビューがモデルに直接バインドされる場合 (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 の構造が変更された場合、UI をそれに合わせて調整する必要はありません。これは、ViewModel がそれらを互いに分離しているためです。

今あなたの質問に。上記の例でわかるように、ジェネリックを使用しましたValueViewModel<T>。このクラスはINotifyPropertyChanged(およびその他のもの) を実装します。新しいPersonインスタンスを受け取ったらReadFromModel(newPerson)、ViewModel を呼び出して UI を更新するだけで済みます。ビューがバインドされている ValueViewModels は、値が変更されたときに UI に通知するためです。

の内部構造を非常に単純化した例を次に示しValueViewModelます。

class ValueViewModel<T> : INotifyPropertyChanged
{
    private T _value;
    public T Value 
    {
        get { return _value;}
        set
        {
            _value = value;
            RaisePropertyChanged("Value");
        }
    }
}

これは、MVVM ライブラリで使用したアプローチです。これには、開発者がコードを設計者の懸念事項から明確に分離する必要があるという利点があります。また、副作用として、すべてのビューとビューモデルで標準化されたコード レイアウトが生成されるため、コードの品質が向上します。

于 2012-04-26T08:37:28.313 に答える
7

ビューがモデルに直接バインドされている場合、サービスが同じインスタンスを使用している限り、モデル プロパティへの変更はビューに反映されます。

ただし、サービスで新しいモデルを再作成する場合は、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);
      } 
 }
于 2012-04-25T21:27:11.600 に答える