In this post (of what may become a series of posts if I find some interest from the community) I compare 2 different approaches for separating view code from business logic in order to reduce the untested surface area while doing TDD.

The Passive View pattern

I have been using the Model View Presenter (MVP) pattern (or more specifically the Passive View pattern) for a long time now, both in the Winforms and WebForms worlds.

The main reasons for this? Testability and separation of concerns. As a TDD adopter, I want to be able to unit test as much logic as I can.

Passive View works fairly well, allowing me to keep the view (usually in the form of a user control) somewhat thin in order to satisfy myself without testing it (you know how difficult/impossible it becomes to unit test a UI screen).

In practice, applications written using Passive View end up having lots of boiler plate code for the communication between the view and the presenter. It also makes it very prone to start putting more knowledge on the view than what I’d like, not only for laziness in trying to avoid forwarding messages (that require very simple processing) to the presenter, but also in some transformations needed to keep the presenter agnostic of the specifics of the UI implementation.

WPF templates to the rescue!

In the Prism project we’ve using the Passive View approach also, as a logical step to adopt WPF when you come from winforms / webforms.

In the last time, though, I have been becoming very fond of another approach that is very easy to implement now using the WPF templating and databinding capabilities that weren’t available before: the Presentation Model pattern. This has been also called Model-View-ViewModel by John Gossman / Dan Crevier (if you haven’t read their blog posts on this topic, you MUST read them).

What I would like to add/highlight in this approach is that in WPF you can enforce keeping your view extremely thin by avoiding the use of UserControls or UI-coupled controls. Instead, you can create DataTemplates of your Presentation Model classes, and those model instances are the objects you’ll add to your Window. When your model gets laid out in the visual tree, WPF will automatically pick up the correct template for that model, and render the model appropriately.

This approach relies extremely on data binding, because there is no code behind at all on the views, just XAML markup.

Most of the times I end up deriving my presentation models from DependencyObject to benefit a lot from dependency properties.

In some cases where UI complexity dictates it, the model may derive from Control instead. "What?!? a model deriving from a Control?". That was my first thought when I came to that possibility, but it was highly biased from my Winforms past. Controls (don’t mistake with UserControls) in WPF are totally lookless and do not rely on the UI, so they can be tested in isolation. To render the appropriate view you’ll need to create a default ControlTemplate (compared to a DataTemplate for plain objects or DependencyObjects). One big benefit about using Controls is that you can maintain a WPF logical tree of presentation models (there are some benefits about this which I won’t cover in this post).

I’m planning on providing you with some code samples in the future, but in the meantime guess what: The latest Prism code drop will be including a spike we did using this approach. You should check it out and see how it feels. Notice that this is just a spike and we are only releasing it in order to get feedback from you guys, and see what is the interest on seeing more of it.

  • http://

    Good stuff. Looking forward to concrete code samples.

  • Mark B

    I was looking this over and I think it’s really good work. I like the idea of attaching the Presenter to the View with a DataTemplate.

    I don’t quite understand what the fuss about the Command Model is. Seems like normal Command Bindings would work. There is the CommandHelper stuff that Dan Crevier did for his ViewModel so you can move the logic into the Presentation layer.

    Keep up the good work.

  • Claudio Maccari

    I like the ViewModelComposition code samples (Change Set 11609) but what about testability ?

  • http://

    Claudio, in the spikes we didn’t include unit tests, because it’s just a proof of concept, although we had testability in mind at all times.
    The thing is that with this approach you can test 100% of your ViewModel, and there is no need to test the view because it’s very slim by design. Well, you could start introducing triggers and complex bindings, but the idea is to try to keep it simple, and make the bindings as simple as possible by exposing the right data from the ViewModel and avoiding complex conversions in the view.

  • John Bennett

    You said: “One big benefit about using Controls is that you can maintain a WPF logical tree of presentation models (there are some benefits about this which I won’t cover in this post).”

    Definitely interested in hearing more about that and how it compares with using DataTemplates. And +1 from me on continuing the Prism work on the ViewModel spike. Thanks!

  • http://

    Could someone please explain to me what a “spike” is? I’ve finally figured out what “grok” means (that word seems to be highly favored by computer geeks), but I’ve never seen an official computer nerd definition of “spike”.

    Thanks in advance (oops, I mean “TIA”)!

  • http://

    A ‘spike’ is a small (and quickly developed) sample application in order to mitigate some risks.

    I like this definition:
    “In agile software development, a spike is a story that cannot be estimated until a development team runs a timeboxed investigation. The output of a spike story is an estimate for the original story.” (from http://searchsoftwarequality.techtarget.com/sDefinition/0,,sid92_gci1306773,00.html)

  • http://panesofglass.org Ryan Riley

    Julian,

    I’ve tried updating the UIComposition Quick Start from the Composite Application Guidance for WPF using the DataTemplate approach, but I cannot get it to work. Can you please ping me offline or post an updated DataTemplate version?

    I can also upload my project for you to look at. The two problems I’m experiencing are:

    1) DataTemplates aren’t being applied to the objects, so I have to include them in App.xaml

    2) The RegionManager fails to find the tab region on my EmployeesDetailsViewModel and thus can’t load the child views.

    Thanks for the help!

  • http://blogs.southworks.net/jdominguez jdominguez

    Hi Ryan,
    1) For DataTemplates to be picked up automatically, you have to merge the resource dictionary with the application’s resource dictionary. You can see how to do this in this blog post: http://blogs.southworks.net/jdominguez/2008/05/first-approach-to-presentation-model-with-datatemplates/
    2) This may be due because as I recall, the tab region you’re trying to get was being created in a scoped region manager. When you’re adding DependencyObjects (DOs from now on) to a region manager (for example in the original quickstart the views are user controls, thus DOs) and using the overload to create a new scoped region manager, the DOs will be assigned a new region manager in the RegionManager.RegionManagerProperty attached property. This property will be inherited by logical children of the DO in the case of views, so that is why the TabControl typically inherits this value, and can be attached to a region manager from XAML.
    In the case of PresentationModels, you could create these as DOs, and listen for changes in the RegionManager attached property, in order to add your region to that RM, or you could avoid all these logical tree things, and explicitly pass the new region manager returned from the call to RegionManager.Add(…) when adding the model to the RM.

    Please let me know if this helps,
    Julian

  • http://panesofglass.org Ryan Riley

    Thanks for your help, Julian. However, both problems continue to plague me. If you have a moment, I posted my solution here. I think the changes to IRegion and IRegionManager are throwing me.

  • jdominguez

    I looked at the code, and here’s my feedback.
    The problem with (1) was that the App.xaml.cs was not calling InitializeComponent() in the constructor, so the application’s ResourceDictionary was not initialized correctly (so the merge didn’t work). try replacing it with this:

    public partial class App : Application
    {
    public App()
    {
    InitializeComponent();
    }
    protected override void OnStartup(StartupEventArgs e)
    {
    base.OnStartup(e);
    Bootstrapper bootStrapper = new Bootstrapper();
    bootStrapper.Run();
    }
    }

    Regarding (2), this is because no one is registering TabRegion in the region manager. You can do this from the model, or from the XAML. If you want to do it from the XAML, apart from adding the RegionName property on the TabControl, add a RegionManager.RegionManager=”{Binding RegionManager}” attribute.
    Even though adding a new dependency property called RegionManagerProperty on the EmployeesDetailsViewModel class works, you could avoid this, and just create wrappers to the original property, like this:

    public IRegionManager RegionManager
    {
    get { return Microsoft.Practices.Composite.Wpf.Regions.RegionManager.GetRegionManager(this); }
    set { Microsoft.Practices.Composite.Wpf.Regions.RegionManager.SetRegionManager(this, value); }
    }

    This way, the region manager will set this property automatically when adding the view to the region.

    I hope this helps, and if you have further conclusions, please let us know :)
    Julian

  • http://panesofglass.org Ryan Riley

    Thanks again for your help, Julian. The first solution worked for loading the resource dictionaries. I can’t believe I missed that. However, I don’t think I follow the second solution. I have updated the solution file (same link as above) and used a region for the EmployeesListViewModel, as well, instead of binding as was done in the spike and as I did previously. I can’t seem to register the model through XAML, and trying to use

    RegionManager.AttachNewRegion(this, "ListRegion");

    doesn’t work either. You mentioned using the RegionManager.Add() but I couldn’t find that and instead looked at RegionManager.Regions.Add() but wasn’t sure where to go from there. If you could look one more time and/or post a code example, that would be very helpful.

    Great work, by the way. We’re using Composite WPF at my office right now, and it’s terrific. We’re currently using the UserControl approach b/c we’ve got it working, but I’d like to move us to the ResourceDictionary approach for views if possible.

  • jdominguez

    Hi,
    It’s great to hear you’re adopting Composite WPF, and I’m glad to help.
    Sorry I wasn’t clear enough on the 2nd question.
    I meant that creating your region from your model feels more presentation model-ish, because you don’t rely on your UI at all to register the region.
    To accomplish this, you could override the RegionManagerProperty metadata from EmployeesDetailsViewModel to provide a custom PropertyChangedCallback that registers the new region:

    static EmployeesDetailsViewModel()
    {
    RegionManager.RegionManagerProperty.AddOwner(typeof(EmployeesDetailsViewModel), new FrameworkPropertyMetadata(RegionManagerChanged));
    }

    private static void RegionManagerChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
    var model = (EmployeesDetailsViewModel) d;
    var regionManager = (IRegionManager)e.NewValue;
    regionManager.Regions.Add("TabRegion", model.TabRegion);
    }

    public EmployeesDetailsViewModel(IUnityContainer container)
    {
    _container = container;
    TabRegion = new Region();
    }

    public IRegion TabRegion { get; private set; }

    Then from your data template you could bind to the TabRegion.Views path from the TabControl’s ItemsSource property.
    In the current scenario it doesn’t matter, but if you were relying on views to become active in the region manager when you select the corresponding tab, this would never happen because we’re not attaching that behavior like the SelectorRegionAdapter does. Nevertheless this could be implemented by creating another attached behavior that binds the TabControl to an existing region (instead of attach *new* region).

    –Julian

  • http://panesofglass.org/ Ryan Riley

    Julian,

    Thanks again. I finally got it working (two weeks ago, I’ve just been delayed in finding the time to post). I’ve posted my solution again, if you’re interested.

    We decided not to take this approach for now since we’d already made so much progress using UserControls as views. We may use this in the future, though. Thanks again!