MVVM – More Lessons Learned from the Trenches

Separation of Concerns

You would think that this was the goal of MVVM. It certainly was one of the goals of the MVC pattern on which MVVM is based. So why do we find it so hard to accomplish? A certain amount of this confusion lies in the early descriptions of the MVVM pattern. Once these little mistakes have entered the collective subconscious of the .Net developer community it is very hard to eradicate them. So, please take your time to define your Model as being a MODEL and not just a single DTO or collection of them. We all know what the View is there for as well as the View Model. Think about the requirements of a Model; its overall status with respect to validation, being dirty and when the Model should inform the View Model of its state change to name just a few important points.

Model Status Change

As mentioned above, one of the primary concerns of the Model is to inform the View Model of its state and any changes to it. Consider that we are loading a Model with data from a number of background services or feeds. It is common to use the Busy Indicator control for the purpose of disabling the View until the data has been prepared in the Model. As we start the possibly long process of loading data we have our Busy Indicator set and the user cannot enter any data into the application (I hope that this can be cancelled or navigated away from, but this is another topic…). Hence we set the Busy Indicator’s IsBusy property to true and off we go to get our data. After a short while our data has been collected and prepared in the Model and we need to inform the user that all is well and that they may enter data into the application. Easy – all we have to do is to set the Busy Indicator’s IsBusy to false. That can be done as the last step in our collection process just after we have received the last block of data. Then we need only pass the completed event of our last data access on to the ViewModel and handle the IsBusy right there in the View Model. WRONG.

Consider a refactoring of the data collection process or even an enhancement in later versions. Now it is time to go hunting for the “correct” moment to set that IsBusy property to false. Beginning to get the picture? The resetting of the IsBusy property is the responsibility of the Model. Hence the model must inform the View Model that data collection has been completed and thereafter raise an event to the View Model indicating this state change. Internally the Model should track the data collection process and NOT misinform the View Model using asynchronous data completion events.

So what is needed? If your MVVM is using the BackgroundWorker a manager needs to be designed which collects all the BGW and registers with each Completed event. Once all the BGW have completed the manager will issue its own event that can be caught by the Model and transformed or just forwarded to the View Model. For those using the async calls directly a little more work needs to be done. However, there are a number of examples out there in cyberspace. Once again they need to raise an event upon completion of all async call which will then be forward to Model and on to View Model.

View Status Change

It always seems difficult to control the visibility and whether a control is enabled or not given a certain state within user’s work process. There seems to be a number of options available from “control” properties, attached properties to using the CanExecute of a control associated Command. Using a Command’s CanExecute for driving the user interface seems at first a simple thing to do. However the difficulty arises when the control does not support a Command property. This leads to a mixing of the three options and hence a confusing implementation within the View Model. Personally, I dislike the CanExecute option and tend to use Commands only for one-way flow from View to View Model. I prepare “control” properties for use when driving the View’s controls and attach these properties to either the control’s enabled, opacity or visibility properties as need be. Hence I have a single method used consistently throughout the UI.

Once this process has been achieved the fun can begin – how can I efficiently control each and every one of these properties without pulling what little hair I have out. Here I would employ a method similar to that described above for the Model status change. Although I have yet to find a framework that is simple and efficient to use I am convinced that the best way currently is to use some form of state machine. Is there anyone out there with another and/or better suggestion?

Validation where?

Basically validation takes place throughout the MVVM. Yes, it can be simplified such that the same validation can be used in the Model as well as in the View Model but this is a very limiting case. Plan ahead and make sure the View that there are enough attached properties or Blend behaviours that implement numeric input, Regex input, length constraints, drag and drop and cut and paste such that even the most avid tester cannot get data into the application that you do not want especially through the “front door”. I have seen enough applications that logically transform the Model data representation into more fields on the form than data actually saved within the Model. Hence there is the need to provide validation on the View Model. Note: this is also apparent in the newer MVVM diagrams from Microsoft where the IErrotInfo interface is implemented both in the View Mode as well as in the Model. Finally, the Model should always be valid and consequently the need for validation at this level – which is usually the first (and sometimes the last) validation to be implement in the MVVM. Conclusion: perform validation at all levels within the MVVM.

Side Effects in Property Setters

This is really not a difficulty with MVVM but a more general problem that manifests itself in UI controls that expose a SelectedItem property (Combo box, List, Data Grid, etc.). The tendency is to perform a two-way data bind to the SelectedItem property in the View Model. When the UI property changes the View Model see this change in the setter of the SelectedItem in the View Model and starts some processing task. This leads to a rather ugly side effect. Many MVVM frameworks recognise this limitation and provide an EventToCommand attached property or Blend behaviour. Hence a Command can be attached to the SelectedItemChanged event and this Command can be readily processed within the View Model. The side effect is eradicated and the SelectedItem can still be accessed for its data but, importantly, it stays a property. Moreover, the use of a Command between the View and the View Model is MVVM conformant. Conclusion: use a Command with the EventToCommand facility to remove side effects in View Model property setters.

I am sure that a number of other items will come up in the future on this topic. But until then, that’s all folks…

 

 

Advertisements

~ by Intelligence4 on July 27, 2011.

 
%d bloggers like this: