ViewLocator - locating the views for a subclassed viewmodel?

Topics: Conventions, UI Architecture
Oct 8, 2012 at 11:45 AM


I'm trying to find an elegant way to locate views for viewmodel subclasses in viewmodel first approach. I would like to use a custom view if it is available for a given viewmodel (which CM does just fine), but if not, then locate the view for the viewmodel's base class and use that instead (which CM doesn't do).

As an example, let's say that I have a ViewModel, named 'MyDataViewModel', which supports multiple contexts that are bound by CM using conventions. For some data, I need to use a subclass of 'MyDataViewModel', e.g. 'ImageDataViewModel', that allows me to replace some of these views easily. Many of the views do not need to be customized at all, though. How should I accomplish this:

MyApp.ViewModels.MyDataViewModel + Context1 => MyApp.Views.MyData.Context1

MyApp.ViewModels.MyDataViewModel + Context2 => MyApp.Views.MyData.Context2

MyApp.ViewModels.MyImageViewModel + Context1 => MyApp.Views.MyImage.Context1

MyApp.ViewModels.MyImageViewModel + Context2 => MyApp.Views.MyData.Context2 (i.e. use the base class view since the view MyApp.Views.MyImage.Context2 doesn't exist).

Currently, CM won't find a view for the viewmodel and context on the last line. Also, it is not very easy to include the base class view in the 'derived' view, due to CM action bindings and other conventions used in the base class view. I've so far tried:

- subclassing from the base view (XAML wouldn't allow),

- including the base class view in the more specialized view (conventions were not applied), and

- creating a ContentControl for displaying the base view and applying the CM binding in code (couldn't get this to work either, controls from the base view didn't come visible).

Any suggestions? Thanks,

   - Jussi

Oct 9, 2012 at 6:12 AM
Edited Oct 11, 2012 at 1:36 PM

This is the best solution I have come up with so far. For some reason I originally preferred a NameTransformer rule, but using the ViewLocator was much easier and I suppose more appropriate as well.

If the default view locator fails to find a view type, I look for a view type for the base class type until one is found.

Any comments, is this the best way to do what I am trying to do?


var defaultLocator = ViewLocator.LocateTypeForModelType;
ViewLocator.LocateTypeForModelType = (modelType, displayLocation, context) =>
  var viewType = defaultLocator(modelType, displayLocation, context);
  while (viewType == null && modelType != typeof(object))
    modelType = modelType.BaseType;
    viewType = defaultLocator(modelType, displayLocation, context);
  return viewType;
May 7, 2014 at 10:43 AM
Very usefull, just what I needed.