tags:

views:

82

answers:

3

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!

+7  A: 

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!

Kieren Johnstone
+1 for "if it works well then it's correct (even if it violates guidelines)"
andyp
No kidding. +1 from me, too.
Rob Perkins
+3  A: 

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}"/>
Groky
+1  A: 

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.

Ray Burns
@Ray Quote:"Such a view can bind directly to the model:Bind TextBox.Text to the Name propertyBind Slider.Value to the Rank propertyBind the Promote button to the Promote() method" Since when does a Model has a method?Bind the Delete button to the Delete() method
Lisa
Virtually all models have methods. A model without methods would be like a person without muscles. Without methods, how would you tell the model to do anything? Would you replace `person.Clap()` with `person.Clap=true` or `PersonOperations.Clap(person)`? Either of these seem awkward at best. Before object-oriented programming there was structured programming, in which you might create a `PersonClap(Person* person)` function, but IMHO the object-oriented way of expressing things is much cleaner.
Ray Burns
The only situation where a model object wouldn't have methods is if it could never *do* anything but was only a raw data record. Such objects are quite rare in real applications. Possible examples might be a raw data point received from a transducer or a bibliographic entry, but even these might have a Delete() method.
Ray Burns
I might flip your question around: When do view models have methods? View models should only have methods when there is something view-specific to do. For example you might have a button in the view that increases the "DayCount" model property or "NightCount" model property, depending on the "IsDaytime" view model property. This would be a good candidate for putting in the view model, because it is specific to the design of the particular view in question.
Ray Burns
The key concept I think you're missing here is a clear delineation between shared "business logic" (or "game logic", etc) in the model versus view-specific concerns in the view model. It sounds like you were treating the model as if it was a raw SQL row. There is no need nor advantage of doing it that way and a huge disadvantage: Either your model logic gets pushed into your view model or you end up creating a third layer.
Ray Burns