3

In my silverlight application the user can create multiple templates of a form. Depending upon the template selected, the form would display a set of views in a particular order. Furthermore, some of the views are "required" if present on the template. The client wants such views to be displayed in a popup form so the user focuses on just those "required" views first before moving onto the other views on the form.

Now, I see myself breaking MVVM pattern for this requirement. Here's why... 1. The ViewModel can read the template from the db, grab the views (using MEF) but to add them to the form, it would need to know the name of the layout grid and add views as a child to that grid. Thats like telling the ViewModel about the UI elements which is against MVVM design pattern.

  1. For the "required" views that must be displayed in a popup, the viewModel would need to create a ChildWindow instance, add the "required" views to it and then show the Childwindow. Also handles Closed/closing events.

I am sure my approach is flawed but am not able to figure out a way to cleanly separate the UI logic from the business logic here. Can someone provide a better approach.

Thanks. A

user559788
  • 303
  • 2
  • 13

3 Answers3

3

IMHO: This is yet another situation where simply adding controllers to MVVM would solve all the problems cleanly. We call it MVCVM (shame that does not equate to valid Roman Numerals) :)

The pattern we are using successfully on all recent projects is to register controllers only, in modules, and initialise them at startup. The controllers are very light/slim and the only thing that needs to hang around for the life of the app listening for, or sending, messages. In their initialise methods they then register anything they need to own (views and viewmodels etc). This lightweight logic-only-in-memory pattern makes for slimmer apps too (e.g. better for WP7).

The problem with just using VMs, as you have found, is that eventually you hit cases where they need to know about views (which is the one thing they should never know about).

The basic rules we follow are:

  • Controllers make decisions based on events
  • Controllers fetch data and place it in appropriate View Model properties
  • Controllers set ICommand properties of View Models to intercept events
  • Controllers make views appear (if not implied elsewhere)
  • View Models are "dumb". The hold data for binding and nothing else
  • Views know they display a certain shape of data, but have no idea where it comes from

The last two points are the ones you should never break or separation of concerns goes out the window.

So far you have a need for your VM to access a database directly (bad), your VMs obtain the views (very bad) and a requirement for your VM to popup another window (insanely bad).

Give it some thought. You may come around to (re)introducing controllers to your MVVM apps. If you want more info just ask.

iCollect.it Ltd
  • 92,391
  • 25
  • 181
  • 202
  • Hello Hitech Magic. Thanks for the detailed suggestion. Given the situation, can you please provide a small and simple example that shows how controllers can help in this situation. I really do not want to take up a lot of your time. A simple example that leads me in the right direction would do. Thanks A – user559788 Jul 30 '11 at 19:29
  • @user559788: The above are a general set of rules (like MVVM). To produce a specific implementation sample I would need more details of the problem you are trying to solve. If you want to send code though my website we can send back something suitable, or you can post more detail in your question. Cheers – iCollect.it Ltd Jul 30 '11 at 19:49
  • Thx for offering to help HiTech. Let me put together a clean sample and send it over to you in a day or two. – user559788 Jul 31 '11 at 02:26
0

In our project we have been following the event subscription mechanism when there is a need to communicate between the view and the view model when UI specific things need to be done. One way to solve your problem is to publish an event on the view model with the list of views as event argument. Or there could be a property which maintains this list, is set on the view model and the event fired when the property is updated. In the view you can subscribe to the event and add the controls to the layout root. This is testable solution and doesn't put anything view specific in the view model.

If you have the liberty of using MVVM framework then you can try something like PRISM or MVVMLight. Prism offers event agreegator while MVVMLight offers Messenger classes which can decouple the communication between view and view model as well as different view models.

Nilesh Gule
  • 1,511
  • 12
  • 13
  • Hi Nilesh, I am using Prism and MVVM but not MVVmLight. I also use event publishing framework offered by prism. I actually am publishing an event when a form is to be displayed. The event has the list of views to be displayed. My "form" view (not the viewmodel) listens for the event and then starts bringing the requested views together and then adds them onto its layout root. I am trying to get away from this logic because it is forcing me to add some code-behind in the form view. Do you have a solution where this logic can be moved over to the viewmodel somehow. – user559788 Jul 31 '11 at 02:25
  • It is not bad to have view specific logic in the code behind. You can watch the MVVM Deep Dive presentation by the creator of MVVM Light Laurent Bungion, where he suggests that a bit of code behind is not bad. I think many people consider it a crime to have code in code behind if you are using MVVM. – Nilesh Gule Jul 31 '11 at 13:19
  • It is absolutely not. What you should be trying to achieve is testability as much as possible by means of abstracting the logic to view model. If there are situation which require you to use code behind it is pefrectly fine to use it. The view model is bound to a view and as such the code behind is aware of the existance of view model. What we shouldn't do is make view model aware of the view. As long as we maintain that separation of concern in my opinion there is no problem in making use of code behind. – Nilesh Gule Jul 31 '11 at 13:20
0

Here's on solution that comes to my mind.

1.Decorate ViewModels with metatags that carry the View name the ViewModel is associated with.

  1. Create a new Class called ViewViewModel that holds two properties

    • View Name
    • ViewModel instance.
  2. On the Form ViewModel, which is responsible for aggregating all the Views together and also bring up a childwindow depending upon the case. Add three properties

    • List FormViews
    • List ChildWindowViews.
    • Action ShowChildWindow

The FormView Model will instantiate required viewmodels, gather the View name from each viewmodel from its MEF metatag and populate the FormView and ChildWindowView properties. Once the Form ViewModel is done processing the request and the two properties have been populated it fires the ShowWindow delegate with true parameter if ChildWindow is not empty.

  1. Form View will do the following

    • The Layout root will have a stackpanel bound to the FormView property. There will be an IValueConverter that processes each entry in FormViews List. For each ViewName, it finds and creates intance of the view. Sets the DataContext to the ViewModel.

    • When the ShowChildWindow action is raised, there's minimal code-behind in Form View that it creates and shows a ChildWindow that is bound to the ChildWindowViews property. ChildWindow property uses the same IValueCOnverter to create instances of requested Views.

How does that sound? Pls comment

enter code here
user559788
  • 303
  • 2
  • 13