views:

1688

answers:

9

I had a question about the VM responsibilities when it comes to pop-ups. When an app is popping a message box or some kind of dialog (with MVVM), the two options that we have are:

  1. putting UI (ShowDialog()) code in VM which seems bad
  2. have VM send some kind of event that UI can subscribe to and display a dialog in the code behind (but we are striving for zero code behind :) )

How do you guys tackle this case? Any input is really appreciated!

+2  A: 

Don't put the UI code in the VM, that just causes a lot of headaches down the road.

You usually have two cases when you want to pop a window or dialogue. Either you are doing it because of a business case, e.g. a detail view on double clicking a list, or it is completely UI based, e.g. popping an options window. In the first case it's best to use an event in the VM, in the later case I just use an event handler. A good rule of thumb is, if you don't need any (significant) VM variables to accomplish the action then you should just use an event handler.

Above all, use your head and trust your judgment, you'll learn which to use soon enough.

Bryan Anderson
A: 

I use events that are handled by the view. I don't like it 100%, but it enables automated testing.

Carlos
A: 

Create a interface for your popup dialog even if you are planning to use messagebox.

At the bottom of a view of your view hierarchy have a method for the presenter to register the class or form implementing the popup.

Have your views call the registered popup.

RS Conley
+1  A: 

A couple of other options not mentioned by others:

A Relay Command

The VM executes a command that I like to call a "relay command". It's a command handled by someone else and the VM doesn't care who. The command execution does nothing but raise the Executed event. Your view would subscribe to this event and display the content in a new Window (the content would be passed as the command parameter).

Note that a relay command is not a routed command. It does not search for a handler in its execution logic. It just raises an event.

A Service

If there are a lot of instances where you need to show something in a window, write a UI service that takes care of it. VMs then depend on this service (which can be easily mocked) to display content in windows.

HTH, Kent

Kent Boogaart
A: 

I'd say the best way to go is define the Popup in XAML and then use a DataTrigger bound to some condition in your ViewModel to hide or display it. Then if you care about handling a return value from the Popup, have an EventTrigger in the Popup manipulate the ViewModel properties to reflect that change.

There's a lot of talk around this kind of area which I think is because people are used to programming in a WinForms world. I've yet to find a solution where i needed any code in the view other than to fetch initial data or set DataContexts

Stimul8d
A: 

I do agree with Carlos that using event subscription in the view is not a good choice. As far as I understand MVVM, it leads to eliminate any code behind from the view and I really like it :). One of the proprs of the MVVM is ability to unit test it. But I still beleive that view model can be tested even if it popups windows. All we need is just to use Window with initialized Content with needed view model. I think there could be 2 possible situations when VM should open new dialog: either to show options/settings window or to show a window which is dependent on the business logic. In the first case new window code is the only code of the command (command for 'Settings' or 'Options' button/menu item). In the second case we have some decision making logic which opens the window. But in any case we can move the code which opens new window into separate method/class and when testing our VM just to mock this method/class. Even more, this separate class can be some kind generic WindowsController which will tracks all windows in the application. But still we can say that view model opens popup using helper WindowsController and view does not know anything else about other windows. All business logic stays incapsulated into model and view model.

Methos
A: 

Have a ViewModel for popup and View as user control. Depending on the complexity of the popup it can be either universal VM or concrete VM for the business case. When trying to display it from parent's VM, create a "host" class for the popups's VM (inherited from Window or Popup), show it and assign the VM to it. Host should have responsibility of locating proper view (f.e. through DataTemplate)

In this case your popup's VM is still testable and the minimal level of coupling with WPF for parent's VM is acceptable, IMO.

Sergey Aldoukhov
+2  A: 

Check out Onyx. This is an M-V-VM library (full disclosure: I'm the author) based on using services and either the Service Locator or Dependency Injection patterns. There's services for MessageBox and common dialogs, and it's pretty easy to add your own services as well.

wekempf
+2  A: 

Hi,

I wonder if this thread will help.

http://stackoverflow.com/questions/454868/handling-dialogs-in-wpf-with-mvvm

Steve the Plant