共用方式為


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.

Overall

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.

MVVM Light

Lots of others 

 

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.

 

Animations

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):

https://blois.us/blog/2009/04/datatrigger-bindings-on-non.html

 

 

Avi

Comments

  • Anonymous
    November 15, 2009
    Good stuff, I know all to well how people come unstuck once they hit some of the points you have raised. And since I am making a MVVM framework (nRoute) for these things, I specifically try and solve such problems - for example, this demo covers dialog issues you've mentioned:http://www.orktane.com/Blog/post/2009/10/23/Web-Xcel-Demo-View-Services-in-nRoute.aspxI'll try and cover more of the scenarios your pointed out here. And I'd love your feedback on that too. Cheers.
  • Anonymous
    November 16, 2009
    Good post.  I'd like to make you aware of one more framework, Caliburn. You can find more information here: http://www.caliburnproject.org/  Caliburn has a ton of samples and in the next few months I am going to be releasing more on my blog: http://devlicio.us/blogs/rob_eisenberg/default.aspx
  • Anonymous
    November 17, 2009
    or ...Be happy with the great flexibility that Silverlight / WPF offer in their binding frameworks, and bind your business objects directly to the UI.Seriously, if MVVM is a hurting, don't do it.Colin E.
  • Anonymous
    November 19, 2009
    I am happy to say my own MVVM framework Cinch.codeplex.com caters for most of this.It may help some of your readers, who knows
  • Anonymous
    December 13, 2009
    Here is yet another Framework that targets the mentioned scenarios:WPF Application Framework (WAF)http://waf.codeplex.comWe use codebehind when it is necessary but try to keep the logic out (I don’t believe that this is a violation of the MVVM pattern because we are still able to unit test). We use controllers which are responsible for the workflow. They are responsible to open dialogs and pass values between ViewModels (Mediator pattern).