Why Complex View Locator?

Topics: Bootstrappers & IoC, Framework Services, Getting Started, UI Architecture
Oct 9, 2012 at 3:26 PM

Hi, I'm looking into Caliburn Micro, and I'm a bit confused with the automatic view locator code.  Why does the default WindowManager not just create a window and set:

window.Content = model;

just like most other MVVM code I've seen?

If I overrode CreateWindow/EnsureWindow to do that (but still connect DisplayName, etc.), would anything else break?  Is there a better and at least a little more future-proof way of doing that?



Oct 9, 2012 at 3:44 PM

Because CM does not use DataTempalates to provide views.

The ViewLocator will instantiate a proper FrameworkElement and place it where it is needed. If you used an approach like yours, an object would have a single UI representation through an explicit DataTemplate, or the framework should be able to locate and provide a specific DataTemplateSelector depending on the context. Moreover, your code requires that a view is always pushed inside a ContentControl/ContentPresenter-derived element... which is not always the case.

If you already have a ton of DataTemplates that you want to re-use, it is better to modify the ViewLocator code to first search for a DataTemplate and, if found, return a ContentControl whose ContentTemplate is set to the retrieved DataTemplate, otherwise the standard behaviour should be applied.

Oct 9, 2012 at 4:07 PM
Edited Oct 10, 2012 at 4:06 PM

I guess I'm still not really clear on why CM doesn't use DataTemplates.  Especially since I still have to do that for any objects within a window.  In my app I'm using AvalonDock as a tabbed interface, so that vast majority of my views are just tabs inside the shell window.  My understanding is that CM's ViewLocator is only used for 'outer' windows or popups.  Is there something I'm missing that would be a more conventional way of implementing tabs, sub-panels, etc. in CM?

Anyway, I do have a pile of pre-existing code.  If I were going to update the ViewLocator, would this be the correct method of doing it?

UPDATE: the original code didn't work, replaced it with better code

var original = ViewLocator.LocateForModel;

ViewLocator.LocateForModel = (model, displayLocation, context) =>
    var dataTemplate = FindDTFromResourceDict(model);
    if (dataTemplate != null)
        //this doesn't work and can be deleted
        //CM loses the datacontext between the ContentControl and your view
        //var cc = new ContentControl();
        //cc.ContentTemplate = dataTemplate;
        //return cc;

        //Instead, get your view directly out of the resource
        var content = dataTemplate.LoadContent() as UIElement;
        if (content != null)
            return content;

    return original(model, displayLocation, context);
Oct 9, 2012 at 4:14 PM

Yes, with this code you should be able to let your DataTemplates have precedence over the standard behavior.

Regarding the fact that DataTemplates are not used explicitly, consider that SL4 does not support implicit DataTemplates, for instance, moreover there are some controls that do not allow DataTemplates at all.

Oct 9, 2012 at 4:44 PM

OK cool.

Thank you for your help!