34

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?

Jan Żankowski
  • 8,690
  • 7
  • 38
  • 52
Chen Kinnrot
  • 20,609
  • 17
  • 79
  • 141
  • In these simple scenarios there is zero benefit of having a viewmodel. If you say wanted to implement an undo function etc then that logic would go in the VM and you would wrap the models properties. – rollsch Feb 01 '17 at 08:49

4 Answers4

38

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.

Ignacio Soler Garcia
  • 21,122
  • 31
  • 128
  • 207
DaniCE
  • 2,412
  • 1
  • 19
  • 27
  • 1
    there is a simple solution for the cons, make the view model a proxy, with all functionality you want to add – Chen Kinnrot Jan 05 '11 at 22:04
  • This is a great example demonstrating a good time to "Wrap" the model and then inject more functionality over the top. – rollsch Feb 01 '17 at 08:42
  • @ChenKinnrot - actually, the "cons" **are** a description of the coding needed to *"make the view model a proxy"*, because the view model must inform the view when any property changes. A library that "injects" code into properties can help, such as [Fody/PropertyChanged](https://github.com/Fody/PropertyChanged). The pain comes if a Model object's property is modified, then any VM(s) of that M object must be told which M property changed, so that they can fire their corresponding OnPropertyChanged, to tell the data-bound V. – ToolmakerSteve Oct 01 '18 at 23:16
22

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.

jason
  • 236,483
  • 35
  • 423
  • 525
  • 2
    The PersonViewModel class has a public constructor with a PersonModel parameter. So the view must Know the model to instantiate the view model... It's not mvvm. The constructor should be internal or only take generic parameters like string or whatever to instanciate the model. – Anben PANGLOSE Mar 24 '16 at 07:56
  • Lets say you change a value in the model (via the UI). As a consequence the model then changes some other values as well (as they depend on it). Would you then fire an OnPropertyChangedHandler and have the VM then update its own properties? This is what I've done and it works well, but I'm new to this and unsure if its bad practice. – rollsch Feb 01 '17 at 08:38
  • Re the above comment. This article seems to implement exactly what I've done. https://msdn.microsoft.com/en-us/magazine/ff798279.aspx – rollsch Feb 01 '17 at 08:41
6

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.

Josh G
  • 14,068
  • 7
  • 62
  • 74
  • Or use the best of both worlds... Define a dynamic base View Model class and a non-dynamic base View Model. Use the non-dynamic for high performance View Models and the dynamic base class for everything else. – Josh G Jan 05 '11 at 14:54
  • remember that DLR is not supported in Silverlight :'( I hate proxy properties too. – Shimmy Weitzhandler Feb 07 '11 at 23:31
  • @Shimmy: That's not surprising. Silverlight is still missing a lot of WPF's greatness. – Josh G Feb 22 '11 at 20:53
5

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.

Deepforest
  • 59
  • 1
  • 1
  • 2
    I agree with you, what's now? – Shimmy Weitzhandler Feb 07 '11 at 23:30
  • It's a relatively straight forward process to wrap an existing Model tree into a VM one. Create a utility that does it, or better yet build it into your own base VM class. Yes, there is some added complexity involved in setting up the VMs and coupling them to their views, but it is worth it. The result is smart code elements at each level of the visual tree. No more searching the visual tree to find someone to handle an operation. – Josh G Feb 22 '11 at 20:56
  • 1
    I have never found a good way to deal with complex operations on individual ListBoxItems without visual hit testing... until MVVM. Once you've built your VM hierarchy and given each VM it's proper references, the ListBoxItems have everything they need to perform their own complex operations. – Josh G Feb 22 '11 at 20:58
  • 2
    If you don't separate the Model from the View why do you need a viemmodel? You could end up setting the Model as the datacontext. – Ignacio Soler Garcia Jan 23 '14 at 10:58
  • @IgnacioSolerGarcia - indeed you could. Note that in practice this means adding to your Model everything that would be in your ViewModel. E.g. inherit from System.Component.INotifyPropertyChanged and fire OnPropertyChanged on every public property's setter. (Or inherit from the appropriate VM base class in any MVVM library, and mark those properties as needed by the MVVM library.) So to me, in effect the question becomes *"Do you need a **model**?"* (Always need a viewmodel). – ToolmakerSteve Oct 01 '18 at 23:23
  • @ToolmakerSteve: for sure you need a model, you don't want your business services to work with VMs but with Models. – Ignacio Soler Garcia Oct 02 '18 at 05:34