MVVM – This might hurt a little…
This is an attempt at a collaborative post; I’ll fill in more data if/when people make suggestions; please add comments on more problems and other/better solutions – I’ll add the links.
Overall, MVVM is very attractive – but all the screen casts I’ve seen avoid some confusing pitfalls that you’ll come up against in the real world. The landscape at the time of writing is a plethora of frameworks that attempt to solve similar problems; I expect the community will settle on a small number eventually, and certain patterns will emerge.
Until then, I hope this will help.
Some things that you take for granted will seem impossible to do in MVVM (without breaking the rules). Sometimes this is due to Silverlight missing WPF features, other times it has nothing to do with that. Most of these holes are pluggable in some sense, which is why…:
Using a Framework
I recommend you use a framework. You can write your own, but please consider that it needs to handle quite a few things in order to solve the various problems in this article.
I can’t recommend which framework to use because I have no experience with them, but I do recommend considering the problems below and finding out how each framework solves them. If the framework doesn’t have a “reference application”, stay away – you’re going to need one.
Here are a few that I know of:
PRISM2.0, which is from the MS Patters&Practices group.
SilverlightFX, by NikhilK. Does alot more than just MVVM; great samples/posts.
Reacting to a click
Scenario: User clicks button; you want something to happen.
Problem: You’re “not allowed” to use the codebehind and an event-handler, so it needs to be done in the ViewModel. However, the ViewModel is ignorant of the view, so it doesn’t know about the button’s existence – it can’t hook into the click event.
Solution: You need support for “commanding”. Put very simply, this is usually a broadcast/listen mechanism where a “command” gets raised by someone, and someone else chooses to listen to it. In this case, the button would raise a command, and the ViewModel would be listening for it, and act.
WPF has it built-in, Silverlight does not – but the various frameworks have tacked it on, and it’s a basic pillar of MVVM.
Opening a dialog
Scenario: You have a listbox, the user double-clicks on an element, and you want an edit dialog to pop up with that element’s data to be edited.
Problem: You’re not allowed to have logic in your code-behind, so you can’t simply react to the event there. So you raise a command, and the ViewModel listens to it… But it’s not allowed to reference a UI component such as a dialog!
Solution: Much as above, you use the broadcast/listen pattern… However, instead of having the ViewModel listen, you have some central app “router” listening, and it knows how to open a dialog.
Passing a value to a dialog
Scenario: Same as above.
Problem: You’ve raised the command, and it knows to open a dialog – but how does it know to pass in the currently selected item from the listbox?
Solution 1: Perhaps your framework allows that item to be set as the command argument as part of the XAML. If so, perfect. If not (or if you need something more complex):
Solution 2: Raise the command, but have the ViewModel listen to it instead of a central “router”. The ViewModel figures out what needs to be passed in (for example, a “CurrentlySelected” bound property on itself), and raises an appropriate command.
Closing a dialog
Scenario: You opened the dialog, the user made their edits and clicked “Save”, then the dialog’s ViewModel called the web service to save the changes. Now the dialog should be closed.
Problem: The last bit of code that ran was on the dialog’s ViewModel; it can’t tell the dialog to close because it has no notion on the dialog’s existence…
Solution 1: Some frameworks have built-in support for dialogs and will handle this.
Solution 2: Cheat; if you’re not a purist, try this: The ViewModel raises an event (“TimeToClose”) with an argument of success/failure. The View’s codebehind subscribes, and closes the view itself.
Scenario: Your app shows a list of servers, and their status is all “good”. The ViewModel loads some new data, and one of the server’s changes to “bad”. The UI needs to react by playing an animation for that server.
Problem: Fundamentally, you don’t want your ViewModel to know anything about animations, storyboards, VisualStates, etc. It changed the data, but all we have on the view side of things is how to display the data; what we really want is the ability to trigger a storyboard, or to bind an element from the ViewModel to a VisualState on a framework element.
Solution 1: You can try to cheat here by using the codebehind, but depending on your exact scenario it might not help at all.
Solution 2: This article seems to do a good job of replicating DataTrigger for Silverlight (although I’ve yet to experiment with this):