MakeCommand
You can handle button-click events in the view model. Expose a property of type ICommand. Update Controls will implement the ICommand interface for you. Use the MakeCommand factory, and pass a delegate into the “Do” method.
public ICommand AddPerson { get { return MakeCommand .Do(delegate { _selection.SelectedPerson = _document.NewPerson(); }); } }
Some commands are not always enabled. Express the conditions under which your command is enabled by passing a lambda expression to the “When” method.
public ICommand DeletePerson { get { return MakeCommand .When(() => _selection.SelectedPerson != null) .Do(delegate { _document.DeletePerson(_selection.SelectedPerson); }); } }
Data bind the property to the button’s Command. When the condition changes, the button will be enabled or disabled. And when the user clicks the button, if the condition is met, it will call the delegate in your view model.
Comments
Menus
Something I got almost, but not quite, figured out is how to do right-click menus. Since I wrote a program with two UIs (WinForms and WPF) I wanted to implement context menus in the viewmodel layer somehow, since the context menus should be the same in both versions. So I came up with an "IMenuItemVM" interface that represents the attributes of a menu item: Text, IsChecked, IsVisible, etc.
Next I made a base class called ContextMenuHub<VM> where VM is a viewmodel class representing the object that was right-clicked. It has an AddMenuItems event; view or viewmodel code can subscribe to this event to pick menu items for a VM when it is right-clicked. It also has a Click event; the view or viewmodel can subscribe to this event to handle when a menu item is clicked. A derived class (e.g. WinFormsContextMenu<VM>) implements the menu-showing behavior. Finally, the presentation model has a ContextMenuHub property (interestingly, the new documentation here does not mention the "presentation model" or "navigation model" anymore... and I didn't really understand the difference between the two anyway.)
Currently I define the menu in the VM layer, placing Click handlers in the view if they need to create or manipulate views, and other Click handlers in the viewmodel.
The main problem with my implementation is that there is no protocol for ordering the menu items or placing separators between them. I am curious if you have ever tried to solve the context-menu problem in the viewmodel layer, or if you think it's a bad idea in the first place.
Responsibilities
I would be interested in seeing your solution. Could you post it to GitHub, or your blog?
I haven't tried to do this before. I've considered the context menu to be the responsibility of the view. But you make a good point about using the same context menus across platforms. Maybe it does belong in the view model after all. If you think about it, it's not so different than putting ICommands in the view model. It's just another manifestation of the Command Pattern.
It seems like you are pretty close to solving the ordering and separation problems. Just honor the order in which the view model returns the IMenuItemVM objects from the event (WinForms) or property (XAML). And then move the methods from IMenuItem to a derived interface IMenuItemCommand. Define another derived IMenuItemSeparator, and perhaps even an IMenuItemSubMenu.
I stopped using the term Presentation Model (coined by Martin Fowler) and started using View Model (coined by Josh Smith). The later has gained wider acceptance. I have similarly switched from Navigation Model to Selection Model to describe the pattern presented here. Navigation Model caused confusion when it was not used for page navigation.