Tuesday, January 29, 2008

In my previous project, we used the Composite Application Block with WPF to decouple our application. Lately I have been thinking alot about this, and found some good material on the subject that I wanted to share. But first, let me give a high-level overview of my previous approach. If you are in need to first learn about MVP, check out this dnrTV video where Jean Paul Boodhoo talks about Model View Presenter.

First off, keep in mind that CAB was not written for WPF and has to be hacked to actually be usable.
Secondly, Acropolis is dead and is being turned into guidance material in the future (think end of 2008!).

Cab exposes workitems, controllers and views. We approached the workitem as a simple configurator, which meant it just grabbed the view it wanted and showed it. That was all the responsibility a workitem got, even in wizard style screens.
The controller was our main class, implementing all the screen logic. It was responsible for retrieving and saving data through services and did not communicate directly with the view. The only communication was through the model, that we dubbed as state.
The view was bound to this state class, which could indeed be seen as a viewmodel-model (see Dan Creviers posts on this subject here). We kept the view as dumb as possible and only let it decide on view specific things, never implementing logic. This means, that the controller could decide when a particular state was prudent (for instance, 'this item is on sale'), but the view gets to decide how to present that item to the world ('wow, I'm going to turn the background to yellow').
The codebehind of the view was only a translation layer between the WPF specific calls (events defined in Xaml) and calls to the controller.

This worked great for us, although in hindsight, we did find that the whole solution was a bit over-the-top. We stuck with it though, and I think it worked out well enough. I feel we could have done without the workitems (in our approach atleast).

Since I'm on sabbatical now, I've been reflecting somewhat more on this issue and found a series of incredible posts by Jeremy Miller on how to build your own CAB. Basically, he points out that it's not that hard to implement MVP in your application by building the pieces you need yourself. The upside would be that CAB is a big monster (I completely agree here),not worthy to be used in your kick-ass application (my own interpretation ;-) ) and building the components you need yourself would buy you a much more lightweight system custom fitted to your problem domain.

While reading all of his posts, I kept feeling that most of what is needed for building a more loosely coupled system is already provided by WPF. The resources system is a possible way to inject dependencies and retrieve them. The routed events and usage of commands is also great. Then just now I've found a post which proves that I am right (and the rest of the world is wrong ;-) ) written by Josh Smith himself, a notable wpf blogger. He shows how he actually uses the resources system to inject classes and even mocks.

My main interest at this moment is to decide how to build big systems with big teams and offer tangible guidance on that subject. One of the most important aspects of that is to Keep It Simple, Stupid! I saw that my team was strugling a bit with bending their minds around the whole MVC concept. This might be attributed to lacking explanations by myself, but at the very least, it was also caused by the feeling it brought-in more complexity then it took away. Certainly the less experienced of the team did not feel the de-coupling was worth it. That is why Jeremy's stand on this felt so 'right' for me. I do think that a simpler solution then CAB would be great.

However, Joshes solution does feel a bit contrived to me. A view would indeed be able to find it's presenter(s), but how does the presenter find it's services? Will they also be defined within the resources? Could be. I find some piece of inversion of control is a more straight forward way to configure your components than 'misusing' the resources functionality. Because that's basically what is being done here.
Keep in mind though, that it is mighty handy to be able to use the injected components within the userinterface without having to do weird things. Say you have an 'edit' button and a controller that was created to manage these things. Your view will want to bind the 'enabled' property to that controller. If it was injected somehow behind the scenes, you will have to find a way to bring it into scope for the button.
We solved this, but it's not pretty!

Another solution being worked on is a WPF specific MVC platform by Rob Eisenberg: Caliburn. His solution does tackle one important issue I have with current systems, which is the communication between the view and the controller. He introduces 'ActionMessages' which can be used in xaml like so:

  1.       <Button Content="="    
  2.               Margin="3">    
  3.          <Engine:Views.AddMessageSource>    
  4.             <Engine:ActionMessage Trigger="Click"    
  5.                                   Action="Divide"    
  6.                                   Return="{Binding ElementName=result, Path=Text}">    
  7.                <Engine:Parameter Value="{Binding ElementName=leftSide, Path=Text}" />    
  8.                <Engine:Parameter Value="{Binding ElementName=rightSide, Path=Text}" />    
  9.             </Engine:ActionMessage>    
  10.          </Engine:Views.AddMessageSource>    
  11.       </Button> 

When the button is clicked, the method 'Divide' will be called on your controller, with two parameters. It's return value will be bound to the result textbox.

Talk about a great idea!! He has used this framework for great succes and I can see why. Incredibly powerful.

However, it does bring in yet another mechanism unfamiliar to your teammembers. Probably worth it though, I'm looking forward to delving into the project and using it myself.
I don't like the introduction of yet another class of things that can go wrong at runtime though: the Action method (here: Divide) should exist on your presenter. If it's not, I'm sure you will only get an error at runtime. As if the binding syntax wasn't enough ;-)

All in all, it seems there is lots of movement in the Microsoft community. People have been thinking about how to build userinterfaces for a long time, and I'm happy to see that this is also the case in the .Net world and very happy to see movement in the WPF camp on this front.

More on this soon!

Name
E-mail
Home page

Comment (HTML not allowed)  

Enter the code shown (prevents robots):