Ben
Ben

Reputation: 1321

WPF - MVVM Viewmodel setup

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:

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.

Upvotes: 3

Views: 2018

Answers (5)

Charleh
Charleh

Reputation: 14002

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.

Upvotes: 5

GazTheDestroyer
GazTheDestroyer

Reputation: 21261

I do not see any problem with having view models that wrap model data objects. Viewmodels do not have to be "one per view". They can represent a row in a list or whatever.

Having said that, I am quite happy binding directly to model objects and I do it a lot. The only time I create a view model to wrap it is if I need extra state per object that is required by the view.

Upvotes: 1

Vyacheslav Yudanov
Vyacheslav Yudanov

Reputation: 451

MVVM is design pattern which have 3 parts: Model, ViewModel, View. DIagram looks like this: enter image description here

http://en.wikipedia.org/wiki/Model_View_ViewModel#Pattern_description

You use ViewModels wrong. Only data for displaying should be in ViewModel. Your Model for example:

public class Project 
{
    public Proforma Pr{get;set;}
}

public class Proforma
{
    public string Name{get; set;};
}

You have View for project display(I inject ViewModel to constructor, tou can use DataContext instead):

public partial class ProjectView
{
    private ProjectViewModel vm;
    public ProjectView(ProjectViewModel vm)
    {
        this.vm = vm;
    }
}

If you want to display proforma name on Project view, you should provide it as string in ViewModel. public class ProjectViewModel { private Project pr; public string ProformaName{get{return pr.Pr.Name;}} }

If you provide Proforma like proforma, your View will know about model. It will be a violation of the pattern.

Upvotes: 2

Marton
Marton

Reputation: 831

You shouldn't create ViewModels for your model objects. Generally speaking, a ViewModel should belong to a UserControl. Its role is to wire your view (your XAML) together with your model (business logic).

In your case, if I understand it correctly, you have a bunch of classes that implement business logic (Project, Shipment etc.). Your ViewModel will have access to the business logic, and provide properties for your view to bind to.

Upvotes: 1

Sebastian Edelmeier
Sebastian Edelmeier

Reputation: 4167

My five cent is that MVVM is a pattern, not a religion. I use it at far as it goes and makes sense. There's many parts where MVVM is undefined (like user interaction from commands), and I read a lot about ViewModels being created just to fit MVVM (which bloats both design and object count). I would suggest you think more DataContext-wise, like "Selections of global interest are kept in a global DataContext, Proforma related data is kept in a Proforma DataContext" and so forth, where DataContext is some sort of ViewModel. In the end, you'll probably wind up rigging those up with UI.

Upvotes: 1

Related Questions