Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multiple ViewModels associated with a single view

Tags:

mvvm

wpf

I have a View that displays a DataGrid which is bound to an ObservableCollection in the ViewModel. For the sake of discussion, let's say we have a Team View containing a Team DataGrid, in which each row represents a Player.

My question is about what data type I should use to represent the players in my Team collection. Is it a good idea for the items in the collection to be ViewModels themselves? In this case, my Team View would be associated with a single Team ViewModel as well as any number of Player ViewModels (in the Team collection).

Does having multiple ViewModels associated with a single View violate any design guidelines for MVVM , and is there a preferred way of implementing this scenario?

Thanks!

like image 331
newdayrising Avatar asked Jul 15 '10 19:07

newdayrising


People also ask

Can one view have multiple Viewmodels?

ViewModel is nothing but a single class that may have multiple models. It contains multiple models as a property. It should not contain any method. In the above example, we have the required View model with two properties.

Can we have multiple knockout models on a single page?

Knockout now supports multiple model binding. The ko. applyBindings() method takes an optional parameter - the element and its descendants to which the binding will be activated. This restricts the activation to the element with ID someElementId and its descendants.

How do you communicate between two Viewmodels?

We will how we can communicate between 2 View Models using Messenger. Then, we will create 2 MVVM Controls by name ControlA, ControlB and try to call a method in which is there is one view model within another view model. Go to Nuget manager and install MVVM Light. Create a Folder structure like below.


4 Answers

No that is fine; each object should be a ViewModel in its own right. It makes for cleaner code, nicer interactions, and remember, if it works well then it's correct (even if it violates guidelines).

I would do it exactly the way you are prescribing. I'd bind my grid to a Team, which would have an ObservableCollection<Player>, where Player is another ViewModel-type class. Each row item would get the Player as its DataContext and so you're still binding to ViewModel properties as you'd expect: and Player can still have public properties for ICommands (likely RelayCommands) for manipulation!

Hope that helps!

like image 120
Kieren Johnstone Avatar answered Sep 23 '22 21:09

Kieren Johnstone


Far from violating guidelines, I think this is recommendated design. At least in my projects you will see this pattern repeatedly.

This pattern comes in particularly useful in conjunction with DataTemplates. For example you could define a DataTemplate in your Application.Resources for your PlayerViewModel like so:

<DataTemplate DataType="viewModels:PlayerViewModel">     <StackPanel Orientation="Vertical">         <Image Source="/Images/Player.png"/>         <TextBlock Text="{Binding Name}"/>     </StackPanel> </DataTemplate> 

And then if you wanted to display a list of players you simply bind a ListBox etc to your TeamViewModel.Players ObservableCollection and you automatically get the above DataTemplate displayed for each player:

<ListBox ItemsSource="{Binding Players}"/> 
like image 28
Grokys Avatar answered Sep 21 '22 21:09

Grokys


I agree with both of the other answers (the ones by Kieren and Groky) but feel they fail to mention a very important consideration in this decision.

You should only create a view model if there is something view-specific about what you are doing. If all you are doing is binding to data and invoking commands which naturally belong on your model, there is no reason to create a view model.

For example, suppose:

  1. Your Player object has a Name property, a Rank property, a Promote() method, and a Delete() method.
  2. Your view is a simple one that allows you to edit the Name and Rank of any player, and also has buttons to promote and delete players.

In this case adding a view model between your view and your model is pointless. Such a view can bind directly to the model:

  • Bind TextBox.Text to the Name property
  • Bind Slider.Value to the Rank property
  • Bind the Promote button to the Promote() method
  • Bind the Delete button to the Delete() method

Note that instead of binding the Delete button to the Delete() method you may want to set its Command to ApplicationCommands.Delete and use a CommandBinding to invoke the Delete() method.

My point here is that in most cases if your models are well-designed there will be no need to insert a view model object. A view model is only really necessary when view-specific state needs to be tracked (such as "current Player"), conversions are too complex to be handled by simple binding, or you need commands that affect several different model objects and/or view model properties at the same time.

In my experience, if the model is correctly designed only about 50% or so of all views actually need a view model, and in the case of items in a list this is more like 20%.

An example of a time when you might use a view model for an item in a list is when you need to keep a separate "selected" flag that is part of your view but not of your model, and the basic functionality in ListBox is not enough.

like image 40
Ray Burns Avatar answered Sep 24 '22 21:09

Ray Burns


By CLEAN COD SOLID principles, it is nice to associate one view model to one view. Separation of concerns should be separated for each view and it's much easier to maintain the codebase in the future. You can do it but it's not recommended.

like image 33
Martin Gelevski Avatar answered Sep 24 '22 21:09

Martin Gelevski