enzom83
enzom83

Reputation: 8310

How should the model be implemented in MVVM?

I'm creating a simple network application that communicates with one or more services, so I planned to use some queues (for outgoing messages and incoming ones), a table, a list containing the status for each active connection, etc.: in other words, these are the data structures needed to ensure the functioning of the application itself.

This application must also be equipped with a graphical interface that shows part of the internal functioning of the application itself: for example, the filling status of queues, the status (detected speed, etc.) of the connections, etc.. According to the Model-View-ViewModel pattern, the model consists of the data to be displayed in the GUI: in this application, the aforementioned data structures represent the model. In other words, the Model implements the business logic of the application.

The ViewModel should implement INotifyPropertyChanged interface in order to notify the View that a change is occurred, but how does the Model to communicate with the ViewModel? After reading this article, I realize that the INotifyPropertyChanged interface is implemented by the model. This answer explains a little more, but it confuses me a bit:

INotifyPropertyChanged - Should go into ViewModel and Model (if needed)

Why, if needed? When should I implement this interface? When should I not implement it?

Moreover, the Dictionary does not implement the INotifyPropertyChanged interface: if I use it, should I wrap it with a class which implements this interface?

Finally, the model should be read-only, meaning that the user does not be able to change the contents of internal data structures using the GUI. How to accomplish this?

Upvotes: 0

Views: 971

Answers (3)

Peter Ritchie
Peter Ritchie

Reputation: 35881

INotifyPropertyChanged (INPC) should never be in the model unless the model is also the ViewModel (i.e. you don't have a "model"). INPC should only ever be in the view model.

The model should know nothing about the view model, and thus can never communicate with it. Only the view model can communicate with the model.

From the UI point of view, only the view model does anything with data; so, if you want the model to be "read only", then just don't implement that in the view model.

Binding would be done with the view model, in which case don't use Dictionary (unless you want to write the code to wrap that in order to bind it). If the Dictionary is in the model, then you should be "wrapping" that in the view model--it's fairly trivial to write an observable wrapper around a collection. In all likelihood your view model isn't going to deal with key/value pairs--it should be dealing with something flat that the UI can handle (and be bound to).

UPDATE:
INPC was introduced for data binding. It decouples a view from a particular concrete class so that it only needs to know about INPC (notice the direction of decoupling). In terms of MVVM this decouples the view from the view model, in the case of PM, this could decouple the view from the presenter, in the case of MVC this could decouple the view from the controller, in the case of MVP this decouples the view from the presenter.

Data binding is a technique of binding data to UI elements. It binds a data source to a target so that the target may request data how ever it sees fit or the source can push data however it sees fit (depending on the type of binding--it could be one-way or static, restricting how often get/push can occur).

Sometimes the necessary nature of the decoupled relationship between the data source and the target lead people to believe data binding isn't a UI concern and data binding can apply anywhere. i.e. a data binding implementation is completely decoupled from a UI. This is generally a mistake. Data binding decouples the view from the specific knowledge of specific classes (this is basic layering and avoidance of cycles, that I won't get into here). But, it doesn't completely decouple the view from the data source. Binding can't happen without the data source--there is still a level of coupling there, it's just the compile-time coupling that has been alleviated (aids in testing, flexibility, robustness, etc. but must be present at runtime in production. i.e. the fact that the INPC implementation can be tested without being bound at runtime to UI elements doesn't mean it's not dependant on a UI framework). The fact that the view is still loosely coupled to the data source isn't the only coupling in this relationship. The data source is loosely (if not less loosely) coupled to the view by way of its UI framework.

Every UI framework has a restriction that access and modification of UI elements must be done on the main, or UI, thread. (at least on Windows; it likely happens on other platforms, I'm just not proficient in any others). With data binding, the source is indirectly bound to the control and any data change directly changes one or more UI elements (depending on the framework you can have intermediaries. Like value converters in WinRT, but their responsibility is to transform or convert data). This means that the data source needs to have intimate knowledge that it is bound to a UI and what type of UI framework it is binding to. This tight coupling to a UI framework clearly couples the data source (still loosely) to the UI.

This means any particular implementation of INPC is really bound to one and only one UI framework. That object can no longer be used anywhere (obviously anywhere is an ideal, it's often impossible to make anything work for every scenario--the point here is high cohesion in more than just one or two scenarios). e.g. if an implementation of INPC is used in a multi-threaded environment then it needs to "marshal" data back to the UI thread before sending out property notifications. In WinForms, that's Control.BeginInvoke, in WPF and Silverlight that's via System.Windows.Threading.Dispatcher. In WinRT, that's via Windows.UI.CoreDispatcher. In all cases the INPC implementation must take a direct coupling to one UI framework. In the case of Silverlight, that's a direct coupling to either the "desktop" Dispatcher or the Windows Phone Dispatcher.

Quality metrics include concepts like cohesion. Cohesion is a measure of how strongly related two units of code are. An implementation of INPC that is used by something other than the UI, due to the nature of all the infrastructure required to support that one particular UI framework, although potentially able to be used outside of the UI, will have low cohesion because all of the code relating to the UI framework will not be used. i.e. it's take on too much responsibility to be completely decoupled from the UI. Yes, you can use an object that implements INPC anywhere and never use the PropertyChanged event, but then you have low coehsion (considered bad).

If I implemented INPC in my model and I wanted to use that model with both my UI and my WCF or web service back end, I either couldn't or my backend would have to take a reference to some UI framework. If I wanted to use that model in another type of UI, I couldn't, because that INPC implemetnation depends on one particular UI framework. I'd have to write another "model"; at which point it's clearly a "view model".

INPC itself is not bound to a particular UI framework (nor should it be). This leads to the misconception that INPC can be used anywhere. Yes, its lack of coupling to high-level namespaces means it can, but the overwhelming usage of INPC is when the target is a UI. I'd challenge any other uses of INPC that don't involve a UI as true "binding". As with any other tool, you can misuse it to get useful results. INPC could be used for projecting data, it could be used for transforming data, etc.; but I believe those are misuses of INPC and really outside the focus of this question...

Upvotes: 0

Gambit
Gambit

Reputation: 2525

  1. INotifyPropertyChanged is primarily implemented by the ViewModel classes. This is to facilitate the data-binding so that the UI controls in the view that are bound to the ViewModel property will be updated when the property is modified.
    In the MVVM design pattern, the relationships are very simple and in a single direction. The View knows it's ViewModel and a ViewModel knows about the Model. If the Model is updated, the ViewModel needs to know somehow so that it can reflect the update and propogate it to the View. One way is to also have the Model implement INotifyPropertyChanged and have the ViewModel implement the corresponding event handler. If all the changes are driven from the UI and being pushed back to the Model, then this is probably not necessary.

  2. You can't really bind to a Dictionary. Using an ObservableCollection would be ideal if that works in your case. Or, you can take a look at implementing an Observable Dictionary along the lines of this: http://drwpf.com/blog/2007/09/16/can-i-bind-my-itemscontrol-to-a-dictionary/

  3. MVVM has provided separation of the Model from the View, so there should be no direct relationship from the View to the Model. The implementation of the ViewModel controls what, if anything would ever get written back to your Model.

Upvotes: 1

Bob Horn
Bob Horn

Reputation: 34297

how does the Model to communicate with the ViewModel

Any way you want it to. In most of the apps we write, the view model makes calls to the business logic layer (the model). However, if you have a need for the view model to be notified immediately (events) of changes to the model, you could implement INotifyPropertyChanged on your model. Or you could simply have the view model subscribe to events on the model.

Moreover, the Dictionary does not implement the INotifyPropertyChanged interface: if I use it, should I wrap it with a class which implements this interface?

You only need to have the view model implement INotifyPropertyChanged. Properties within the view model (dictionary) will simply invoke NotifyPropertyChanged (or whatever your implementation looks like).

Finally, the model should be read-only, meaning that the user does not be able to change the contents of internal data structures using the GUI. How to accomplish this?

Don't provide the user the functionality to let them change the data. Make the binding one way, or simply don't provide them an API for making changes.

Upvotes: 2

Related Questions