WPF - MVVM Viewmodel setup

c#, mvvm, viewmodel, wpf

Solution

A viewmodel should be a model of the user interaction for a particular area of functionality

For instance, if you have a project list page and the user can do certain things like delete a project, edit a project, print information about the project then you should design a viewmodel that contains the data and actions associated with this interface:

e.g. the viewmodel should contain:

 * A bindable container for the project data (list of projects)
 * Actions that handle edit/delete interaction
 * An action to handle the print functionality

The actual functionality inside these actions may not be contained within the viewmodel (the VM may have received injected services such as the print service or the project repository) but the responsibility of execution of these actions lies with the VM.

It may also be necessary to wrap each data item (project) in a viewmodel so that additional interaction dependent properties/actions can be added - such as the 'selected' property (imagine the user wants to multi-select a load of projects in the view - you could add a selected property to the ProjectViewModel which will wrap each project which makes binding easy)

You may end up with something like the following:

public class ProjectOverviewViewModel 
{
    public IList<ProjectViewModel> Projects { get;set; }

    public ProjectViewModel SelectedProject { get;set;}

    public void EditSelected() 
    {
       // Code to open edit page for the selected project
    }

    public void Print()
    {
    }
}

and the `ProjectViewModel` with a selectable property

public class ProjectViewModel
{
    // Either put the actual data item in here and wrap it:
    public Project Project {get;set;}

    // Or copy properties onto the viewmodel using automapper or some other mapping framework...
    // or manually :(
    // e.g. properties mirrored from the entity object:
    public int ProjectId { get;set;}
    public string ProjectName { get;set;}

    // The selected property - now your 'Selected' logic is a function of the view/viewmodel
    // not the entity. The entity should only be concerned with data persistence
    public bool IsSelected {get;set;}
}

You may also want to composite viewmodels together in order to build more complex views. Imagine you have a projects page and a "users involved in a project" page, and you wanted another page that showed both side by side (and allowed you to click a project which would refresh the users pane) - this is possible by compositing the viewmodels (by creating another viewmodel which contains the two viewmodels as properties and wires up the interaction between the two)

public class ProjectAndUserOverView
{
    public ProjectOverviewViewModel ProjectOverview {get;set;}
    public ProjectUsersViewModel ProjectUsers {get;set;}

    // Code here to listen for property changes in ProjectOverview and if SelectedProject changes
    // call ProjectUsersViewModel to refresh the data for the selected user
}

Ultimately you are just modelling the user interaction, and the more modular you can make it, the easier it will be to make cleaner more maintainable code

There are some good MVVM frameworks - my personal fave is Caliburn Micro as it makes the above very easy (it heavily uses conventions by default) and is easy to get into.

Problem

I'm having some issues with the setup i'm currently using with my mvvm application. Having seen some posts on here, i get the feeling i may be doing this slightly wrong. I have several models which contain lists of child models such as: - Project - Contains a list of proformas - Proforma - Contains a list of shipments orderedItems - Shipment - Contains a list of Containers - Container - Contains a list of packages We do not have any viewmodels that relate directly to these model currently, we instead simply have viewmodels that represent the list of models, for example we have a proformalistviewmodel which simply contains a list of proformas. My issue is, that with this setup i'm a little confused as to what viewmodel should own which data, for example the ProfomalistViewModel has a reference to the currently selected Project, all the data management for these models (the loading and saving of the list of proformas) is done via manager classes which are loaded via DI. My question is should i instead be following what I'm seeing and having a ProjectViewModel which contains a list of proformas, and a ProformaViewModel which contains a list of shipments and ordereditems and so on. The reason for this, is that originally none of the models we're linked, projects did not own a list of proformas they were instead loaded separately via the managers using the selected project ID (using a relational db) and we're currently changing the models to the system i described above.

Original source