.NET & Funky Fresh

Syndication

News

  • <script type="text/javascript" src="http://ws.amazon.com/widgets/q?ServiceVersion=20070822&amp;MarketPlace=US&amp;ID=V20070822/US/bluspiconinc-20/8001/8b68bf4b-6724-40e7-99a5-a6decf6d8648"> </script>
MVVM and The Origins of Caliburn

Recently Glenn Block asked some questions of the community concerning what support Microsoft should offer for the MVVM design pattern in WPF/Silverlight.  I’d like to answer that question here, but in a round-about manner.  I’m going to use this as an opportunity to talk about the origins of Caliburn.

About two years ago I entered an article in a contest on dotnetslackers about a prototype framework I had developed several months earlier during my free time.  The sample application for the article is manufactured, but the framework was built for a real application I was working on then.  At that time, I was writing a GUI test runner for NSpecify framework.  I had been doing WPF development for over a year, though not for paying contracts (I built some really cool samples such as a WF designer, an interactive fiction viewer/editor, a partial implementation of the Office 2007 ribbon and a multi player online game) and was using this project to experiment with some new architectural ideas.  I had long since become frustrated with the typical code-behind model and had been looking for ways to move away from it.  Being heavily influenced by John Gossman’s article on MVVM, I began making greater use of Commands to enable databinding of UI to actions.

Here’s the progression I went through and suspect that many WPF developers can identify with:

  1. Started by manually wiring events and handling them in the code-behind.
  2. Factored logic out of the code-behind and into some sort of presentation class (Presenter, VM, etc).  Event handlers became a pass-through to methods on the presentation class.
  3. Moved away from events and towards commands.  Created custom commands that hung off the presentation class and were wired to the UI through databinding.
  4. Got tired of creating lots of commands after about 5 minutes and implemented a DelegatingCommand pattern to enable databinding on the view side, with a pass-through to a standard method on the presentation class.
  5. Got tired of instantiating and wiring delegating commands after about 15 minutes and created a fluent interface dedicated to the task.  The code looked something like this:
    public DelegatingCommand Save
    {
        get { return Execute.AsCommand(DoSave).If(CanDoSave).Async(); }
    }
    
    In fact, you could see the implementation of this in some early versions of Caliburn.

To answer Glenn’s first question:

Where does the platform help? Where does it hinder?

Even though the fluent interface is a pretty efficient way of binding models and views, it is still fairly limited in its capabilities.   With commands you are limited to elements that implement ICommandSource only.  So, if you want to have code execute on a ListBox.SelectionChanged event, you have to revert back to events and code-behind.  You could try and rig something up by using InputBindings/CommandBindings which exist on all UI elements, but using gestures to simulate control-specific events is kludgey.  Furthermore, InputBindings/CommandBindings have limitations due to the fact that they either are not DependencyObjects or don’t implement DependencyProperties and cannot be bound as easily, thus you have to use some sort of static class mechanism.  Furthermore, commands can only have one parameter and RoutedCommands are terribly confusing and IMHO an overly complex solution to the problem.  All of this is a bit shady and quite round-about in general.  This leads me to a rather simple answer to Glenn’s second question:

What can we do in the platform to make life easier?

What we really want to do is bind the view directly to the methods themselves.  It would be nice if we had a mechanism by which we could bind any .NET event, routed event, gesture or command with one consistent syntax.

Caliburn’s implementation of RoutedMessaging and Actions is my attempt to solve this very problem in the OSS space.  Actions was the first feature I developed for Caliburn (although there are quite a few more now and many more to come) and it remains one of the most used.  Here’s a snippet from one of Caliburn’s sample apps, demonstrating some of the syntax:

<Button Content="Example 1"
    Message.Attach="Divide(left.Text, right.Text) : DivideResult.Text" />
<Button Content="Example 2"
    Message.Attach="[Event Click] = [Action Divide(left.Text, right.Text) : DivideResult.Text]" />

Both these snippets do the same thing, the second is just more explicit about the details.  Here’s what all this does:

  1. Wire up to the “Click” event (Caliburn determines this to be the default in Ex1)
  2. Send an “Action Message” whenever the “Click” event fires (again Caliburn knows that Actions are default in Ex1)
  3. When the action executes, take the Text properties of the controls with names “left” and “right” and pass those values as parameters to the “Divide” action (a method on a class).
  4. Perform type conversion on the parameters.
  5. Take the return value of the action and databind it back to the Text property of the control with its name set to “DivideResult”

This demonstrates binding directly to methods from events.  But you can also trigger actions based on an ICommandSource’s command execution:

Message.Attach="[CommandSource] = [Action Divide(left.Text, right.Text) : DivideResult.Text]"

Or by gesture:

Message.Attach="[Gesture MouseAction: LeftClick, Modifiers: Control] = [Action Divide(left.Text, right.Text) : DivideResult.Text]"

The “trigger” aspect of Caliburn is completely pluggable.  In fact, the ICommandSource trigger implementation was a user submitted extension, much thanks to Marco Amendola.  Additionally, you can plug the right part of the expression.  So instead of just triggering actions, you can also trigger commands (or anything you wish to extend it too):

Message.Attach="[Event SelectionChanged] = [ContainerCommand ShowMessage(title.Text, message.Text)]"

Caliburn can resolve commands from the container (ContainerCommand) , resource dictionaries (ResoureceCommand) or through databinding (BoundCommand) and the command’s trigger doesn’t have to be an ICommandSource nor is it limited to one parameter.  In fact, commands in Caliburn are built on top of actions.  Which means they inherit a host of other features as well, such as ASP.NET MVC-style rescues and filters (which are extensible) and extensible ActionResults (called IExecutableResult in Caliburn).  You can also decorate your action/command with an [Async] attribute and Caliburn will call it on a background thread, and automatically marshal the callback onto the UI thread (you even have control over the background task’s progress and cancellation).

As a developer, it was really important to me that I have a consistent way of wiring user interactions to my model.  Furthermore, I wanted the same syntax for both WPF and Silverlight (and yes, that took a lot of work in SL2).  This brings me to a key point, whatever Microsoft builds, the public API should be the same for both WPF and Silverlight.

What role do developers / designers play in your application of ViewModel?

I think that the only way to have a strong UI is through iterative development.  This means constant communication between the development team and the client, but also constant communication between the developers and the designers.  Keep in mind that a View and its ViewModel are a highly cohesive unit.  This means that a designer is going influence what your ViewModel looks like.  What I would really like is a way for Views to be more easily bound to their ViewModels.  Christopher and I have often talked about how nice it would be for Caliburn to have a Cider/Expression plugin that let you wire views directly to the ViewModel (both properties and methods).  And that definitely describes something I would like to see from Microsoft in this area.  The next phase in designer/developer interaction in WPF and Silverlight is a ViewModel rather than code-behind centric tooling experience.


Posted 05-18-2009 10:51 AM by Rob Eisenberg

[Advertisement]

Comments

chris donnan wrote re: MVVM and The Origins of Caliburn
on 05-18-2009 11:47 AM

I have this general issue w/ WPF being generally type weak. I do not mind a dynamic type system, but the more code I put into my XAML, the more I have a hard time testing it, the more my compiler does not help me find issues etc. How do you feel about putting small type-unsafe embedded mini-dsls into your XAML files like your above examples?

Tuna Toksoz wrote re: MVVM and The Origins of Caliburn
on 05-18-2009 1:18 PM

The more I spend time with Caliburn, the more I like it. I am still a beginner though and I don't like xaml programming (shy!)

Rob Eisenberg wrote re: MVVM and The Origins of Caliburn
on 05-18-2009 3:08 PM

@chris

I understand you completely.  It's something I've struggled with.  However, Caliburn's model gives me such a productivity increase, it's hard for me to justify not using it.  Also, one way that Caliburn's actions are different from WPF databindings is that they will fail fast.  I have Caliburn.Testability which verifies property bindings, as I've found myself making more mistakes on properties than on methods.  In a future version I am hoping to be able to verify actions as well.

Dave wrote re: MVVM and The Origins of Caliburn
on 05-18-2009 5:29 PM

Being unable to bind to a method (as is needed for an eventhandler) makes code separation far more difficult than it needs to be.

The proper solution is to have the binding engine directly support binding events to methods.  Click="{Binding OnSaveClicked}" is simple and more importantly uses the same syntax as the code-behind Click="OnSaveClicked".

Rob Eisenberg wrote re: MVVM and The Origins of Caliburn
on 05-18-2009 5:41 PM

@Dave

Such a thing would be nice, but it is impossible with the current version of WPF and Silverlight.  It still wouldn't solve all problems because sometimes you need your datacontext to be different from your action context.  Additionally, a straight databinding solution would make it difficult to proxy the method calls if you wanted to use rescues, filters, async execution, etc.  So, if MS ever does implement something like this, I would want hooks into the invocation mechanism.

DotNetShoutout wrote MVVM and The Origins of Caliburn - Rob Eisenberg - Devlicio.us
on 05-18-2009 8:26 PM

Thank you for submitting this cool story - Trackback from DotNetShoutout

Glenn Block wrote re: MVVM and The Origins of Caliburn
on 05-19-2009 9:25 AM

@Rob, nice post, and really appreciate the feedback. Several of the points you made are on the money, and are also things we're looking it.

@Chris the weak binding of XAML is a double edge sword. In our new view model work we're looking to bring a better validation story for binding between views and vms.  This won't solve all problems, but will certainly bring compile time safety to a good subset. Over time the story will hopefully get better and better.

9eFish wrote MVVM and The Origins of Caliburn
on 05-19-2009 11:10 PM

9efish.感谢你的文章 - Trackback from 9eFish

About The CodeBetter.Com Blog Network
CodeBetter.Com FAQ

Our Mission

Advertisers should contact Brendan

Subscribe
Google Reader or Homepage

del.icio.us CodeBetter.com Latest Items
Add to My Yahoo!
Subscribe with Bloglines
Subscribe in NewsGator Online
Subscribe with myFeedster
Add to My AOL
Furl CodeBetter.com Latest Items
Subscribe in Rojo

Member Projects
DimeCasts.Net - Derik Whittaker

Friends of Devlicio.us
Red-Gate Tools For SQL and .NET

NDepend

SlickEdit
 
SmartInspect .NET Logging
NGEDIT: ViEmu and Codekana
LiteAccounting.Com
DevExpress
Fixx
NHibernate Profiler
Unfuddle
Balsamiq Mockups
Scrumy
JetBrains - ReSharper
Umbraco
NServiceBus
RavenDb
Web Sequence Diagrams
Ducksboard<-- NEW Friend!

 



Site Copyright © 2007 CodeBetter.Com
Content Copyright Individual Bloggers

 

Community Server (Commercial Edition)