views:

483

answers:

6

I'm trying to get to grips with MVVM and so I've read a bunch of articles - most focus on the View -> ViewModel relationship and there's general agreement about what's what. The ViewModel -> Model relationship and what constitutes the Model gets less focus and there's disagreement. I'm confused and would like some help. For example, this article describes the Model as a business object whereas this article describes a class which manages business objects. Are either of these right or is it something else?

A: 

The value added by the model is its decoupling from the ViewModel and the View. Think if you had to construct and maintain business logic in the ViewModel you would have lots of duplicate code.

For instance - if you had a car game with a GearBoxView (a control in the CockpitView), CarViewModel and CarModel - the advantage of abstracting what is in the CarModel from the CarViewModel is that the CarModel can be used in the WorldViewModel and any other ViewModel. The CarModel can have relationships with other Models (GearsModel, WheelModel, etc).

Your question specifically asked about using a Model as a business object or to manage business objects: my answer is it can do both - and should be responsible for both.

Heres an example

public class WorldModel //Is a business object (aka game object)
{
    private List<CarModel> _cars;
    public List<CarModel> Cars
    {
        get //Here's some management of other business objects
        {
            //hits NetworkIO in a multiplayer game
            if(_cars == null)
            {
              _cars = myExternalDataSource.GetCarsInMyGame();
            }
            return _cars;
        }
    }
    public Level CurrentRaceCourse { get; set; }
    public CourseTime TimeElapsed { get; set; }
}
Skawful
I would disagree that the ViewModel and the Model and decoupled. In fact, I would say they are just the opposite.
Anderson Imes
You agree with it in your answer though... to be clear by decoupling I mean there aren't dependencies of the model in the viewmodel and the view (ie: you databind to the VM and the M but the model shouldnt point the otherway around).
Skawful
Yes, that's clearer.
Anderson Imes
+2  A: 

I think you are on the right track. The "model" is vague in a lot of cases because it is different things to other people, and rightly so.

For me, my business objects that come back from my WCF service I consider my model. Because of this my projects don't have that pretty file structure with the holy trinity of namespaces: *.Models, *.ViewModels, and *.Views. I personally consider objects coming back from business logic or anything of that nature the "model".

Some people tend to lump both the business objects and the business logic together and call that the "Model", but I find that a little confusing because I picture a Model to be sort of more static than I do business logic, but it's semantics.

So when you look at examples of MVVM projects and don't see anything very clearly "Model", it's just because folks treat them differently. Unless an application is very standalone, I would actually be very suspicious of an application with an actual *.Model namespace, to be honest.

The other thing that is great here is that many times you already have an investment in these types of business objects and I think a lot of people see "MVVM" and immediately assume they need to start defining the "M", even though what they already have is perfectly fine.

The confusion between a Model and a ViewModel is pretty common, too. Essentially I know I need a ViewModel if I need a combination of data and behavior. For example, I wouldn't expect INotifyPropertyChanged to be implemented on a Model, but I would a ViewModel.

Anderson Imes
I though you had a good answer until the end. I don't really understand why you wouldn't expect INotifyPropertyChanged to be implemented on a model? I often implement this on the model, how else would you expect multiple views to be notified of changes to the core business data? (eg your model could be an Employee class. If Employee.Name is changed for a particular instance you want the View/ViewModel to be notified of that change).
Ashley Davis
Because that is a behavior. Models don't need view-specific behavior. It's just not a responsibility of the Model. For instance, if you create a WCF service reference, those objects don't have INotifyPropertyChanged implemented. If you need that level of behavior, you would implement that type as a ViewModel.
Anderson Imes
This is not to say that this is not a common question to have. Popular opinion is that your Model should have very little to do with WPF (that way it's reusable in a non-WPF context, etc). There are quite a few threads on SO on this topic: 1) http://stackoverflow.com/questions/839118/composite-guidance-for-wpf-mvvm-vs-mvp 2) http://stackoverflow.com/questions/772214/in-mvvm-should-the-viewmodel-or-model-implement-inotifypropertychanged 3) http://stackoverflow.com/questions/857820/big-smart-viewmodels-dumb-views-and-any-model-the-best-mvvm-approach
Anderson Imes
A: 

There are a lot of different implementations and interpretations.

In my mind, however, the value of the ViewModel comes from coordination.

The Model is representative of business data. It encapsulates scalar information, as opposed to process.

The View is obviously the presentation of the model.

The ViewModel is a coordinator. In my opinion, the job of the view model is to coordinate between the view and the model. It should NOT contain business logic, but in fact interface with business services.

For example, if you have a view that is a list of widgets, and the widgets are grabbed from a service, then I'd posit:

The Model is a List<Widget> The View is a ListBox bound to the ViewModel property Widgets The ViewModel exposes the Widgets property. It also has a IWidgetService reference it can call to in order to get those Widgets.

In this case, the view is coordinating with a business object so the view doesn't have to know anything about it. The model should be ignorant of view models, views, and every thing else ... they should exist independent of how they are used. The IWidgetService would get bound to the view model using some source of dependency injection container, either constructor injection with Unity or an import using MEF, etc.

Hope that makes sense ... don't overload your viewmodel. Think of it as a coordinator that understands business objects and the model, but has no knowledge of the view or how business process is performed.

Jeremy Likness
+2  A: 

From the other answers it should be obvious that the relationship between ViewModel and Model is somewhat fuzzy. Be aware that there is nothing stopping you from having ViewModel and Model in the same class, and when your requirements in a particular area are simple enough maybe this is all that you need!

How you structure the separation between ViewModel and Model will very much depend on the needs of the project or software that requires it, how demanding your deadlines are and how much you care about having a well structured and maintainable code base.

Separating ViewModel and Model is simply a way of structuring your code. There are many different ways of structuring your code, even within this pattern! It should be no surprise then that you will hear different approaches preached by different programmers. The main thing is that the separation can help to simplify and make reusable the independent portions of code. When you have cleanly separated business data, business logic and presentation logic you can easily mix, match and reuse your views, logic and data to create new UIs. The separated and simplified code is also often easier to understand, test, debug and maintain.

Obviously not everyone will agree with this answer. I think that is part of the inherent fuzziness of the problem. In general you need to consider and trade-off the advantages versus the costs of having a separation between ViewModel and Model and know that it is not always a simple task to decide what goes in the ViewModel and what goes in the Model. It will probably help to lay down some ground rules that you or your organisation will follow and then evolve your rules as you understand which level of separation best suits your problem domain.

I think it is worth mentioning that I used to use a similar approach to MVVM when programming Windows Forms and the fact the WPF has more direct support for this (in the form of data binding and commands) has really made my day.

Ashley Davis
I agree with most of your post, but there are some inconsistencies. The primary one is that your code should be reusable and independent, but also that you should mix your ViewModels and Models if it makes sense. If your model is meant to be reused (like say, in a WinForm or ASP.NET app), then mixing WPF-specific behaviors like INotifyPropertyChanged and your Model is going to inhibit this ability.
Anderson Imes
One of the main points that I want to get across is that whether you have a combined ViewModel/Model or two layers of abstraction, or even more layers of abstraction depends on your needs and requirements. There is no easy way to explain how to make that separation. It requires some experience, some ideals as to how to write well structured code but also depends very heavily on how much time you have to attend to it and what your deadlines are, etc. You may have another opinion however, which I imagine is completely valid in your situation.
Ashley Davis
By the way I have used INotifyPropertyChanged on both my Windows Forms and WPF models, and these days I also use ObservableCollection where it makes sense (pre-WPF I had a similar implementation of my own). There is probably a more perfect level of code separation than that, but with perfection comes cost and I use these tools in my data model because I can then bind the UI directly to the model where it makes sense. I would agreed that this may not be a perfect separation of concerns, but I have to make code to deadlines and find that my approach works pretty well in practice.
Ashley Davis
We all have deadlines ;-)
Anderson Imes
A: 

I think of the model as something that contains the smallest units of business entities. The entities in the model are used not only across the view models in my application but even across applications. So one model provides for many applications and, for those applications using MVVM, many view models.

The view model is an arbitrary collection of entities from the model that are brought together to serve whatever the view needs. If a view requires 2 of these and 1 of those, then its view model provisions them from the model. Generally, I have 1 view model per view.

So a model is like a grocery store. A view model is like a shopping cart. And a view is like a household.

Each household has unique requirements. And each household has its own shopping cart that cherry picks what the household needs from the grocery store.

MarkB
A: 

My thoughts

(The "Model")

Have one model. Just data no methods (except if apt for the platform some -simple- getters/setters).

(The "View Model")

To my mind the rationale for a view model is:

(1) to provide a lower-RAM-requirement backup copy of fields so views hidden behind other views can be unloaded and reloaded (to conserve RAM until they reappear from behind views covering them). Obviously this is a general concept that may not be useful or worthwhile to your app.

(2) in apps with more complex data models, it is less work to lay out all application fields in a view model than to create one reduced model corresponding to the fields of each possible data change, and easier to maintain, and often not significantly slower performance wise.

If neither of these apply, use of a view model is inapt in my view.

If view models are apt, have a one to one relationship of view models to views.

It may be important to note/remind/point out that with a lot of UI toolkits if the exact same "String" object is referenced twice (both in the model and the view model) then the memory used by the String object itself is not double, it is only a little more (enough to store an extra reference to the String).

(The "View")

The only code in the view should be (the required) to show/hide/rearrange/populate controls for initial view load and (when user is scrolling or clicking show/hide detail buttons etc) showing/hiding parts of the view, and to pass any more significant events to the "rest" of the code. If any text formatting or drawing or similar is required, the view should call the "rest" of the code to do that dirty work.

(The "View Model" revisited)

If the (...facts of which views are showing and...) the values of view fields are to be persistent ie survive app shutdown/restart, the view model is part of the model :--: otherwise it is not.

(The "View" revisited)

The view ensures that the view model is as synch'ed with the view in terms of field changes as is appropriate, which may be very synched (on each character change in a text field) or for example only upon initial form population or when user clicks some "Go" button or requests app shutdown.

(The "Rest")

App start event: Populate the model from SQL/network/files/whatever. If view model persistent, construct views attached to view models, otherwise create initial view model(s) and create initial views attached to them.

On commit after user transaction or on app shutdown event: Send model to SQL/networkl/files/whatever.

Allow the user to ("effectively") edit the view model through the view (whether you should update the view model on the minutest change of a character in a text field or only when the user clicks some "Go" button depends on the particular app you are writing and what is easiest in the UI toolkit you are using).

On some application event: the event handlers look at the data in the view model (new data from the user), update the model as required, create/delete views and view models as required, flush the model / view models as required (to conserve RAM).

When new view must be shown: Populate each viewmodel from the model just after the viewmodel is created. Then create view attached to view model.

(Related issue: what if any data set primarily for display (not editing) should not be entirely loaded into RAM?)

For sets of objects that should not be entirely held in RAM cause of RAM use considerations, create an abstract interface to access information on the overall count of objects and also to access the objects one at a time.

The interface and its "interface consumer" may have to deal with the number of objects being unknown/estimated and/or changing depending on the API source providing the objects. This interface can be the same for the model and the view model.

(Related issue: what if any data set primarily for editing should not be entirely loaded into RAM?)

Use a custom paging system through a slightly different interface. Support modified bits for fields and deleted nits for objects - these kept in the object. Page unused data out to disk. Use encryption if necessary. When editing of set done, iterate it (loading in pages at a time - one page can be say 100 objects) and write all data or only changes in transaction or batch as appropriate.

(Conceptual significance of MVVM?)

Clean platform-agnostic way to allow and lose data changes in views without corrupting model; and to allow only validated data through to the model which remains as the "master" sanitised version of data.

Crucial to understanding the why is that flows from view model to model are conditional on data validation of user input whereas flows in the opposite direction from model to view model are not.

The separation is achieved by placing code that knows about all three (M/V/VM) into a core object responsible for handling application events including startup and shutdown at a high level. This code necessarily references individual fields as well as objects. If it didn't I don't think easy separation of the other objects can be achieved.


In response to your original question, it is a question of degree of interrelationships of validation rules on update of fields in the model.

Models are flat where they can be but with references to submodels, directly for one-to-one relationships or through arrays or other container objects for one-to-many relationships.

If the complexity of validation rules is such that merely validating a successful user form fill or incoming message against a list of field regular expressions and numeric ranges (and checking any objects against a cached or specially fetched copy of relevant reference objects and/or keys) is enough to guarantee that updates to business objects will be 'with integrity', and the rules are tested by the application as part of the event handler, then the model can just have simple getters and setters.

The application may perhaps (best) do this directly in-line in event handlers where the number of rules is so simple.

In some cases it may be better even to put these simple rules in the setters on the model but this validation overhead is then incurred on database load unless you have extra functions for setting without validate. So for simpler data models I tend to keep the validation in application event handlers to avoid writing these extra setters.

But if the rules are more complex either:

(a) a single method taking a special object that is really a composite of the usual business objects containing data for myriad field changes is written for each complex model change, and the method can succeed or fail depending on validation of the rules - facade pattern;

or

(b) a "dry run" / hypothesis / "trial" copy of the model or a subset of the model is created first, setting one property at a time, and then a validation routine run on the copy. If validation is successful, the changes are assimilated into the main model otherwise the data is discarded and an error raised.

The simple getter/setter approach is in my view preferred when analysing each individual transaction unless the vast majority of updates for your app are complex, in which case one can use the facade pattern throughout.

The other way the model ends up getting more complex than a bunch of fields with (possibly) simple getters/setters is if you start "enhancing" classes' getters/setters (with an O2R mapper tool), or adding extra aspects like calls to transaction monitoring APIs, security APIs (to check permissions, for logging etc), accounting APIs, methods that pre-fetch any related data needed for a get or set, or whatever upon get or set. See "aspect-oriented programming" for an exposition on this area.

Martin Rolls