web-dev-qa-db-ja.com

MVVMでは、すべてのViewModelが1つのモデルに結合されていますか?

MVVM実装では、すべてのViewModelが1つのModelに結合されていますか?

プロジェクトにMVVMパターンを実装しようとしていますが、Viewが複数のModelsからの情報を必要とする場合があることに気付きました。

たとえば、UserProfileViewの場合、そのUserProfileViewModelにはUserAccountModelUserProfileSettingsModelUserPostsDataModelなどの情報が必要になる場合があります。

ただし、MVVMについて読んだほとんどの記事では、ViewModelは依存関係注入を介して1つのモデルのみで構成されています。したがって、コンストラクターは1つのモデルのみを受け取ります。

複数のViewModelから情報を取得する必要がある場合、Modelsはどのように機能しますか?または、MVVMでこのような状況が発生することはありますか?

PS:私はPrismまたはUnity Frameworkを使用していません。私が取り組んでいるプロジェクトに、PrismやUnityを使用しない同様のパターンを実装しようとしています。そのため、これらの機能の一部がどのように機能するかを正確に理解する必要があります。

37
Carven

MVVMパターンについての私の理解では、唯一の実用的な要件は、ビューがすべてのデータを(おそらくバインディングメカニズムを介して)ViewModelのプロパティから取得することです。 ViewModelは、そのビュー用に特別に作成したクラスであり、必要に応じて自身を生成する責任を負います。ビューのActiveRecordのように考えることができます。

そのため、プロパティが表示するデータを取得するためにViewModel内で何をしてもかまいません。いくつかのサービスをクエリするか、1つ以上のビジネスエンティティモデルを読み取るか、その場で生成するか、または上記のすべてを実行することで取得できます。機能的なビューを作成するためにこれらすべての組み合わせを必要とすることは完全に正常です。

他の表示パターンと同様に、重要なのは、画面にデータを表示するプロセスと、そのデータを取得するプロセスを分離することです。これにより、プロセスの各部分を個別にテストできます。

編集:依存関係のフローの小さな、しかしうまくいけば完全な例を次に示します。

// Model/service layer

public class MyModelA
{
  public string GetSomeData()
  {
    return "Some Data";
  }
}

public class MyModelB
{
  public string GetOtherData()
  {
    return "Other Data";
  }
}

// Presentation layer

public class MyViewModel
{
  readonly MyModelA modelA;
  readonly MyModelB modelB;

  public MyViewModel(MyModelA modelA, MyModelB modelB)
  {
    this.modelA = modelA;
    this.modelB = modelB;
  }

  public string TextBox1Value { get; set; } 

  public string TextBox2Value { get; set; }

  public void Load()
  {
    // These need not necessarily be populated this way. 
    // You could load an entity and have your properties read data directly from it.
    this.TextBox1Value = modelA.GetSomeData();
    this.TextBox2Value = modelB.GetOtherData();
    // raise INotifyPropertyChanged events here
  }
}

public class MyView
{
  readonly MyViewModel vm;

  public MyView(MyViewModel vm)
  {
    this.vm = vm;
    // bind to vm here
  }
}

// Application layer

public class Program
{
  public void Run()
  {
    var mA = new MyModelA();
    var mB = new MyModelB();
    var vm = new MyViewModel(mA, mB);
    var view = new MyView(vm);
    vm.Load();
    // show view here
  }
}
41
Alex J

ビューモデルでは複数のモデルを使用できます。ビューモデルの目的は、ビジネス/データレイヤー(つまり、モデル)を抽象化することです。

ただし、通常、複数のモデルを使用すると、ビューが大きすぎることを示します。独自のビューモデルを持つユーザーコントロールに分割することもできます。

14
jgauffin

ビューモデルには「ビューロジック」が含まれているため、ビューに表示したいものはすべてビューモデルを通じて公開されます。異なる「モデル」からのデータを表示したい場合は、ビューモデルがこれを集計し、ビューをバインドできます。

mvvmの主な目的はbtwユニットテストでした。これは、UIなしでビューロジックを簡単にテストできることを意味します。

編集:なぜあなたは思いますか:

ViewModelのコンストラクターには、Viewのパラメーターが1つだけあります

EDIT2:

mvvmを操作する2つの主な方法があります。1つ目は「最初に表示」、2つ目は「最初に「表示モデル」」です。もちろん、両方を組み合わせて、ニーズに最適な方法を選択できます。

4
blindmeis

ViewModelは、多くの場合、複数のモデルを使用します。それ自体がビューの「モデル」です。

ユーザーが住所などの個人情報を入力するプロフィール画面を考えてみましょう。アドレスが「addresses」テーブルに格納され、残りが「profile」テーブルに格納されている場合、ViewModelはProfileモデルとAddressモデルの両方を使用して、統合されたViewModelを作成します。

jgauffin が彼の回答で述べたように、多くの場合、ユーザーコントロールを使用して1対1の関係を実現できますが、この100%の時間を試すことで、不必要な複雑さを導入することもできます。

2
Andrew Grothe

ビュー、ビューモデル、および他のすべてのモデルクラスの違いを理解していることを確認します。 ViewModelは、ビューをバインドできるデータで満たされたモデルオブジェクトです。ビューにデータを提供するためだけに存在します。これにより、ViewModelオブジェクトが単体テスト可能になり、ビジネスロジック全体がビューから分離されます。したがって、ビュー自体を使用せずにビジネスロジックを完全に開発でき、ビューを別のビューを構築または使用してViewModelオブジェクトのプロパティにバインドするだけでビューを置き換えることができます。たとえば、ビューが空のテキストフィールドでいっぱいの場合、テキストフィールドの内容をビューモデルのさまざまなプロパティにバインドできます。

通常、実際にはビューモデルは1つだけです。ただし、複雑すぎる場合は、バインドされたオブジェクトのサブプロパティを Binding to ViewModel.SubClass.Property(sub-property) で説明されているように使用できます。

ViewModelは、さまざまなソース、ビジネスオブジェクト、データベースなどからビューに返すデータを取得できます。

2
Akku

通常、モデルごとに1つのViewModelがあります。これらのViewModelには、モデルのデータを処理するためのロジックが含まれています。反対に、どのビューにも独自のビューモデルがあります。つまり、これは次のことを意味します。

class ModelA 
{
    bool TestValue{get;set;}
}
class ViewModelA<ModelA>
{
    ValueViewModel<bool> TestValue{get; private set;}

    public ViewModelA(ModelA model) 
    {
        base.Model = model;
        this.Initialize();
    }
}

class ModelB 
{
    string Username;
}
class ViewModelB<ModelB>
{
    ValueViewModel<string> Username{get; private set;}

    public ViewModelB(ModelB model) 
    {
        base.Model = model;
        this.Initialize();
    }
}

これらは、モデルをカプセル化するViewModelです。ビューには独自のViewModelがあります。

public ViewModelForExactlyOneView
{
    public ViewModelA{get;set;}
    public ViewModelB{get;set;}
}

質問に答えるために、ViewModel1はViewModelAおよびViewModelBを参照します。したがって、ビューはViewModel1.ViewModelA.TestValueからデータを取得できます。

1
PVitt