Multiple ViewModels associated with a single view - 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!

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!

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

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:
Your Player object has a Name property, a Rank property, a Promote() method, and a Delete() method.
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.

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.

Related

WPF/MVVM - binding collection of child controls

some advice from he WPF/MVVM gurus, pls.
I come from a Windows Forms background and I am porting a personal project from VB.NET to WPF. I started with a straight re-write with the logic going in the code-behind files, albeit with a discrete Data Access Layer.However then I discovered MVVM and that I was 'doing it all wrong' and should be abstracting the logic into a View Model accessing a data model. I think I've absorbed the new paradigm and my code behind files are now (nearly) empty.
(As an aside, I buy into the rationale behind MVVM, but I'm not sure about the 'easier to test and debug' argument, due to all the 'plumbing' of routed events and commands etc, I appreciate the need but it seems to me sometimes to obscure rather than clarify what is going on. But I a very much a novice, maybe it will come with practice.)
Anyhow - here's what has got me scratching my head; the app is a dive planning/recording tool for scuba diving centres. Logically, its like a calendar or diary app, with the need to record the time and site of each dive and who went on each dive. The main screen resembles one page of a diary and I have a user control that encapsulates the dive info. On change of selected date, the diary page is cleared and re-populated with the dives for the new selected date. The View Model retrieves and exposes a list of 'Dive' objects (classes) for the new date. The container is a Stackpanel and I want to clear its children and then create and add the new Dive user controls to the child controls collection.
My question is - where is the appropriate place to do this - View code behind or View Model? The former is relatively easy but seems to me to break the pattern, but I am stumped by how I would achieve it in the view model. The sequence needs to be
User selects a new date (calendar control)
Handle the selected date change event
Clear Stackpanel child controls
Retrieve list of dives for new date from db and generate a user control for each
Add user controls as stackpanel child controls.
I guess what I'm asking is - is there a way of binding the collection of child controls to a collection of objects in the view model such that it responds dynamically - and is this a sensible approach?
The appropriate way to do this would be to wrap your StackPanel in an ItemsControl and bind the ItemsSource to your Dives of the selected day. When your DivesOfThatDay is changed (make sure to implement INotifyChanged or a DependencyProperty, or use an ObservableCollection), every single entry will be generated automatically.
<ItemsControl ItemsSource="{Binding DivesOfThatDay}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type Dive}">
<!-- Your Template -->
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
In MVVM you should always avoid generating Controls in Code-Behind. Your View should take the Data from your ViewModel and do that on its own - otherwise MVVM would be kind of useless. In your case it should work like this:
User selects a new date in the view
Because the date control in the view is bound to some property in your viewmodel, that property gets updated.
The viewmodel reacts to this change by clearing its current collection of dives and fetching a new one.
The model data (from the database) gets encapsulated in a viewmodel (a Dive) and added to the dive collection in the viewmodel
The view (ItemsControl) gets notified of this change (via INotifyPropertyChanged, INotifyCollectionChanged or whatever) and tells its ItemContainerGenerator to update the controls.
The ItemsContainerGenerator generates a view for every Dive in your viewmodel and adds it to the stackpanel.
Or in short V → VM → M → VM → V

INotifyPropertyChanged on Model classes

Is it generally desirable to implement INotifyPropertyChanged on Model classes, ViewModel classes, or both? Is it possible to implement on Model only ,not on Viewmodel? If not possible model then why
Basic rule is - There is no hard and fast of any architecture, you can modify things to suit your needs that's why some architectures are more desirable.
for your exact needs go through this
and in this discussion, there are enough points to cover both arguments, see which one matches your project..
this might help you to implement..
You must understand the meaning of INotifyPropertyChanged. It's purpose is to raise notification from target to source when you define Binding in WPF. DependencyProperty and INotifyPropertyChanged are related for autoupdation for the concept of binding. If you need to bind the property on a viewmodel to view you have to implement a notification mechanism to notify to UI if there is change in Viewmodel. Same rule is applied for model to View.
Suppose you want to code in .CS file like Viewmodel.Name =" my new name" and expect that TextBox should display the changed name.
<TextBox Text="{Binding ViewModel.Name} "/>
Here view model need to implement INotifyPropertyChanged.
<TextBox Text="{Binding Model.Name} "/>
here model need to implement INotifyPropertyChanged
Hope it clarifies.
It might be worth noting in this discussion that Microsoft themselves add INPC in their own models e.g. the classes automatically generated when you susbscribe to a web service. I've seen it various other places as well, including a vague recollection of it somewhere in their EF stuff. I myself add it automatically to my DAL entities using Castle Proxy so that I don't have to duplicate everything in the view model, although you can also use things like Fody etc to add it to the IL in a post-processing step.

How to present a collection of objects in a listbox in WPF

I have a collection of objects that I want to present. How can I do this? A listbox would do but each object has many attributes which I want to present. I already bound a listbox to a collection and I have all my objects listed. My question is regarding the visualization of the listbox and if the listbox is the correct thing to use or there is something else that I should use.
I find the existing answers to be a bit lacking, normally one would not process collections or boil their items down to a string, at the very best you would do some dynamic manipulation using a CollectionView (e.g. sorting, grouping), but normally you use Data Templating to display the individual items which allows you to use all their properties.
Further there are several controls which work well with collections, firstly you need to know if you want selection, if not an ItemsControl is a good choice, otherwise you should use a ListBox or ListView.
ListViews are normally employed if you have different views for your objects, e.g. a details view and a thumbnail view. You can use the ListView.View for this, there is one existing view in the framework, the GridView, which offers columns. What Matthew Ferreira suggested is exactly what you should not do with a ListView since you want to make the templates dependent on the current view, in fact that code does not even compile since DataTemplate can only have one child.
ListViews are supposed to encapsulate the view logic in their view so it can be changed at will. If you decide to use a ItemsControl or ListBox then setting the ItemTemplate is what you want to do. Read the Data Templating overview i linked to, it makes for a good starting point.
You might want to consider using a ListView control instead. ListView has support for columns if you are planning on showing several properties from your object. You can use the ItemTemplate property to format the display of your object. For example:
<ListView ItemsSource="{Binding Path=myObjectCollection}">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Title}"/>
<CheckBox IsChecked="{Binding Path=ShouldCheck}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
This example assumes that your object has the properties Title and ShouldCheck.
Your collection of object is probably to be viewed as your model. The usual thing in WPF is to add a ViewModel that translates and exposes the model data into a form suitable for binding. Depending on what you want to do, your VM could e.g. format each object into a string representation and then expose it as a collection of strings that the Listbox can bind to and display.

What is the best approach to assign Data Context using MVVM?

I was looking for best approach to set data context property. I found three ways
Assign data context on View (either on XAML or code behind).
Assign data context on ViewModel through constructor.
Use some configuration that takes view and view model reference and bind data context on run time through some infrastructure classes.
Which is the best option among this in terms of loosely coupled, maintainable? Or Is there any best approach?
I personally like this approach because it makes me have to write less code :). It basically uses an IValueConverter to lookup which view to use whenever a wpf control needs to present a ViewModel visually and the IValueConverter sets the datacontext for you. It also shows you how to create a datatemplate that allows you to require WPF to utilize this converter by default, something like this:
<DataTemplate DataType="{x:Type ViewModels:ViewModelBase}">
<ContentControl Content="{Binding Converter={StaticResource MyConverter}}"/>
</DataTemplate>
the 4. way would be a DataTemplate.
i think the best approach is the one which fits best in your current situation.
if i have viewmodel first dynamic scenarios i use datatemplate/contentpresenter or with view first i take your way one and so on...

WPF events, commands or using both

I am constructing my app infra structure, and finding it hard to achieve a very basic behavior - I want to raise events from different user controls in the system and being able to catch those events on some other user controls that listens to them. For example i have a user control that implements a TreeView. I have another user control that implmements a ListView. Now, i want my ListView to listen to the TreeView, and when the selection is changed on the TreeView, i want to repopulate my ListView accordingly.
I also want this to happen even if the ListView is not located within the TreeView on the WPF logical tree.
PLEASE HELP!!
Thanks,
Oran
Use data binding.
If the content of the list view is stored inside the object shown in the tree view you can just bind into the tree SelectedItem property.
Otherwise bind the tree SelectedItem to a property in your view models (or your window!) and in the setter of this property change the list that is bound to the list view ItemSource property.
You can see the technique in this series on my blog the post I linked to is the last post with the code download link, you'll need to read from the beginning of the series if you want the full explanation.
EDIT: Here's how I did it in one project: (the GridView definition removed since it's not relevant here)
<TreeView
Name="FolderTree"
Width="300"
ItemsSource="{Binding Root.SubFolders}"
ItemTemplate="{StaticResource FolderTemplate}"/>
<ListView
Name="FileView"
ItemsSource="{Binding ElementName=FolderTree, Path=SelectedItem.Files}">
</ListView>
The list bound into the tree view's ItemsSource is of objects that have 3 properties: Name (that is bound to a TextBlock in the FolderTemplate), SubFolders (that is likewise bound to the HierarchicalDataTemplate.ItemsSource property) and Files that is bound to the ListView using {Binding ElementName=FolderTree, Path=SelectedItem.Files}
Note that non of the lists are observable collections (because in this project they never change) but are loaded lazily (on-demand) by the properties getters (because in this project they are expensive to load).
This is the point where the added complexity of MVVM (Model-View-ViewModel pattern) can start to pay off. What you need is a publish/subscribe infrastructure, and MVVM Light has that, along with good MVVM structure that doesn't get overly complex. Prism is another good WPF/Silverlight infrastructure foundation with publish and subscribe support.

Resources