Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MVVM: Should a VM object expose an M object directly, or only through getters delegating to M's getters?

the best way to explain is with example so:

this is the model

public class Person 
{
    public int age;
    public string name;
}

this is the view model

public class PersonVM
{    
}

my question is:
should the vm expose the person to the data template or encapsulate the model properties with his own properties?

like image 455
Chen Kinnrot Avatar asked Jul 11 '09 20:07

Chen Kinnrot


4 Answers

There is not a general agreement about that question. For example it was one of the open questions about MVVM formulated by Ward Bell here:

Is the VM allowed to offer the V an unwrapped M-object (e.g., the raw Employee) ? Or must the M-object’s properties (if it is even permitted to have properties!) be exposed exclusively through the surface of a VM wrapper?

The principal advantages of not directly exposing the Model in the VM are:

  • you can use it as a "converter on steroids", formating the model values in a convenient way for the view

  • you can inject other funcionality related to the user interface, like data validation messages, undo redo,..

The cons are:

  • you will have to duplicate a lot of code to expose all the models properties in the viewmodel.

  • if you bind the view control to the viewmodels property, you will send the propertyChanged events from the viewmodel. But what happens if the models property change from other source different from the viewmodel setter? Then it has to notify the viewmodel so you end with 2 OnPropertyChanged, one in the model and one in the viewmodel... quite complex!

So for me the correct answer is: it depends on your requirements.

like image 128
DaniCE Avatar answered Nov 14 '22 04:11

DaniCE


The view model should declare its own properties and hide the specifics of the model from the view. This gives you the most flexibility, and helps keep view model-type issues from leaking into the model classes. Usually your view model classes encapsulate the model by delegation. For example,

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

class PersonViewModel {
    private PersonModel Person { get; set;}
    public string Name { get { return this.Person.Name; } }
    public bool IsSelected { get; set; } // example of state exposed by view model

    public PersonViewModel(PersonModel person) {
        this.Person = person;
    }
}

Remember: the model shouldn't know anything about the view model that is consuming it, and the view model shouldn't know anything about the view that is consuming it. The view should know nothing about the models lurking in the background. Thus, encapsulate the model behind properties in the view model.

like image 21
jason Avatar answered Nov 14 '22 04:11

jason


An interesting solution to this was proposed by Robert McCarter in MSDN volume 25.

http://msdn.microsoft.com/en-us/magazine/ff798279.aspx

He uses a dynamic View Model to provide a layer on top of the Model while avoiding proxying all of the Model properties.

If your problem space doesn't require high performance (dynamics do incur a performance hit), this is an excellent solution. The View does not need to know anything about the Model, but the View Model does not have to proxy properties that are being provided "as is." At any time properties can be added to the View Model to wrap the Model properties without modifying the View or the Model. Read the article for more details.

like image 6
Josh G Avatar answered Nov 14 '22 03:11

Josh G


Having a ViewModel for any Model could be worse than that. What if you have a hierarchical structure of a Model, or even a simple collection? In that case you'll have to iterate through all models and build a ViewModel instance per-model, and also to register notify-change events or other events. IMHO, this is completely insane, and unreasonable. As DaniCE said, you’ll end up with lot of code and a big headache.

like image 5
Deepforest Avatar answered Nov 14 '22 04:11

Deepforest