In MVVM, is every ViewModel coupled to just one Model?

26,377

Solution 1

In my understanding of the MVVM pattern, the only practical requirement is that the View gets all its data from the properties of a ViewModel (probably through a binding mechanism). The ViewModel is a class that you craft specifically for that view, and takes on the responsability of populating itself as required. You could think of it like ActiveRecord for the view.

As such, it doesn't matter what you do inside the ViewModel to obtain the data that its properties should show. You could get it by querying some services, reading one or more business entity models, generating it on the spot, or all of the above. It's perfectly normal to need a combination of all these things to make a functional view.

As in any presentation pattern, the point is just to separate the process of showing some data on the screen, from the process of obtaining that data. That way you can test each part of the process separately.

Edit: Here's a small but hopefully complete example of the flow of dependencies.

// 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
  }
}

Solution 2

You can use multiple models in a view model. The purpose of the view model is to abstract away the business / data layer (i.e. the model).

However, using more than one model usually indicates that the view is too large. You might want to split it into user controls (which have their own view models).

Solution 3

a viewmodel contains the "view logic" - so all you wanna show on the view is exposed through the viewmodel. if you wanna show data from diffenrent "models" then your viewmodel agregate this and the view can bind to.

the main purpose from mvvm was btw unit test. this mean easy testing of view logic without UI.

EDIT: why do you think:

ViewModel only has one single parameter for the View in its constructor

EDIT2:

there btw two main approaches to work with mvvm, first is "View First" second is "Viewmodel First" you can of course mix up both and choose the best approach for you needs.

Solution 4

A ViewModel may and in many cases does use multiple Models. It is itself a "Model" of your view.

Consider a profile screen that a user enters their personal information including address. If the address is stored in an "addresses" table and the rest in a "profile" table, then the ViewModel uses both the Profile and Address models to create a unified ViewModel.

As jgauffin mentioned in his answer, many times you can use user controls to achieve a one to one relationship, but you can also introduce needless complexity by trying for this 100% of the time.

Solution 5

I would make sure you understand the difference between view, viewmodel, and all other model classes. The ViewModel is the model object that is filled with data that the view can be bound to. It just exists to provide data to the view, which makes the ViewModel object unit-testable, and the whole business logic separate from the view. So, you can develop your business logic entirely without using the view itself, and can replace the view with just building or using another view and binding to the ViewModel object's properties. If a view is full of empty text fields for example, the contents of the text fields can be bound to different properties of the view model.

There usually really should only be one view model. BUT if it's too complex, you can use subproperties of the bound objects like described in Binding to ViewModel.SubClass.Property (sub-property)

The ViewModel can get the data it returns to the view from a lot of different sources, business objects, databases, whatever.

Share:
26,377
Carven
Author by

Carven

Updated on June 17, 2020

Comments

  • Carven
    Carven almost 4 years

    In an MVVM implementation, is every ViewModel coupled to just one Model?

    I am trying to implement the MVVM pattern in a project but I found that sometimes, a View may need information from multiple Models.

    For example, for a UserProfileView, its UserProfileViewModel may need information from UserAccountModel, UserProfileSettingsModel, UserPostsDataModel, etc.

    However, in most articles I read about MVVM, the ViewModel only consists on one Model via Dependency Injection. So the constructor takes in only one Model.

    How would the ViewModel work when it has to get information from multiple Models? Or would such a situation ever occur in MVVM?

    PS: I am not using the Prism or Unity Framework. I am trying to implement similar patterns into a project that I am working on which doesn't use Prism or Unity. That's why I need to understand exactly how some of these things work.

  • Andrew Grothe
    Andrew Grothe over 11 years
    huh? You may want re-write that to be a bit more clear. It sounds like your saying a View should have multiple ViewModels to me.
  • Carven
    Carven over 11 years
    Thanks! But how would multiple models be injected into the ViewModel? From the UML diagrams, I observe that usually, the ViewModel only has one parameter that takes in a single Model.
  • jgauffin
    jgauffin over 11 years
    Depends on what you use. Any IoC can inject multiple models. Same goes for Caliburn.Micro (my favorite MVVM framework)
  • Carven
    Carven over 11 years
    hmm...I don't understand how would the IoC be able to inject multiple models into the ViewModel when the ViewModel only has one single parameter for the View in its constructor? I'm looking at the structure that of something like: i.imgur.com/ZKEDz.png
  • venkat
    venkat over 11 years
    @xEnOn: Your graph is confusing. Normally, the ViewModel doesn't have a dependency on the View that is using it. It's the View that depends on the ViewModel, and takes it as a constructor argument. The point of the IView abstraction, is that should you want to access a different view in your ViewModel, you can do so without breaking encapsulation.
  • Carven
    Carven over 11 years
    @IliaJerebtsov I got the diagram from waf.codeplex.com/wikipage?title=Model-View-ViewModel%20Patte‌​rn Because I am not using any IoC framework at the moment, and I am implementing the pattern on my own, I need to understand how it works. From what I read, the ViewModel class only takes in one Model through its constructor. If something else could inject multiple Models into ViewModel, I wanna know how is it done? Would the ViewModel maintain a List of Models then?
  • venkat
    venkat over 11 years
    @xEnOn: I assume that by Model, you mean some kind of object that will let you get information from some other part of the program (eg: a domain model service). There is no restriction that you should only depend on one of these, and it's perfectly fine to have more than one constructor parameter in your ViewModel class. You would store references to these in your ViewModel for later use, in readonly fields, for example.
  • venkat
    venkat over 11 years
    @xEnOn: See my answer for a code example of what I'm talking about.
  • Carven
    Carven over 11 years
    Thanks! The example really helps to clarify the idea a lot. +1 :)
  • PVitt
    PVitt over 11 years
    Is "every View has it's own ViewModel" not understandable? Sorry for my bad language skills, but I fully agree with you. One view is linked to exactly one view model. But this ViewModel itself can reference several other ViewModels.
  • PVitt
    PVitt over 11 years
    @agrothe: I tried to clarify the use of ViewModels. Sorry for my bad language skills...
  • Andrew Grothe
    Andrew Grothe over 11 years
    It was more the "To answer your question, ViewModel1 refers to ViewModelA and ViewModelB" line that is confusing. The code helps clarify what you are trying to say.
  • O.O
    O.O over 8 years
    Disagree. Why do user controls have their own view models? Does a textbox control have its own view model? No.
  • jgauffin
    jgauffin over 8 years
    User Controls do have view models. At least mine. why would you not give them view models? And don't see your point with textbox controls? I'm talking about handling business code.
  • PVitt
    PVitt over 6 years
    Never use a model in a view! MVVM is exactly about this design flaw and wants to address it with the ViewModel concept.
  • I.K.
    I.K. almost 4 years
    This works fine but how to notify the MyViewModel class when the data is changed in the ModelA and ModelB classes? How to bind MyViewModel class to ModelA and ModelB class variables?
  • venkat
    venkat almost 4 years
    Usually, your model only changes when the UI tells it to change. You might be clicking a Save button somewhere, and you can use that to refresh the data afterwards. However, sometimes that's not easy to do. If your model changes by itself by getting data from an external service, or if it's modified by some other part of the program, the easiest way to go about it is to expose an event in your model/business layer, and listen for that event in the ViewModel.
  • venkat
    venkat almost 4 years
    Make sure to unsubscribe when the window is closed, or the window will be bound to the lifetime of the model. Best way about it is to implement IDisposable on the ViewModel, and dispose it on close, or better yet, let your dependency injection container handle it.