Silverlight navigation: get rid of the view-model-locator
Let’s start from the beginning
I’m building a sample application for a friend in order to see if it is possible to have a completely OOB and offline Silverlight application running on a Mac using a document database (RavenDB in this case, a special version) as backend.
On the other side I’m using the same spike to start the Radical Presentation Silverlight 5 implementation, if you recall the first time we spoke about it we state that the main pillar should be simplicity.
Simplicity, IMHO, means also friction-less and friction-less in a Silverlight application, for example, can be translated to “navigation application” that uses all the out-of-the-box services provided by the Silverlight infrastructure such as the navigation framework.
Why?
Easy peasy…fast startup is the answer, startup Visual Studio…create a new project and you expect to be up and running just adding a bunch of references.
Well…all the samples I’ve found out there, the majority of them, does 2 main things:
- some of them get rid of the default navigation framework and start building their own…
- some of them use the built-in services and introduce that piece of crap called “view-model-locator”…
- some of them does both of the above… :-/
Basically the main reason is that view-model-locator sounds too much like service-locator that for me is pure evil…view-model-locator is everything other then friction-less, you introduce a class, with pure stupid properties, for the only purpose of linking the view and the view model in a view first scenario where you do not have any control on the view creation (the navigation infrastructure has it).
So?
If you remember some time ago we spoke about the ability, using PostSharp, to intercept the instantiation of a class. Why not using that really simple type load interceptor to do something like:
TypeLoader.Engine.AddInterceptor( new DelegateTypeLoadInterceptor()
{
IsInterestedInHandler = ( o, m ) =>
{
return m == TypeLoadMomentum.AtConstructorExit && o is Page && o.GetType().Name.IsLike( "*View" );
},
InterceptHandler = ( o, m ) =>
{
var viewType = o.GetType();
var aName = new AssemblyName( viewType.Assembly.FullName );
var vmTypeName = String.Format( "{0}.{1}Model, {2}", viewType.Namespace, viewType.Name, aName.FullName );
var vmType = Type.GetType( vmTypeName, true );
var p = ( Page )o;
p.DataContext = container.Resolve( vmType );
}
} );
we basically say:- every time a view, that is a Page, and whose name ends with “View” is instantiated we are interested in intercept the constructor at the end of the instantiation process;
- we use a convention to determine the view model type name given the view type name;
- we resolve the view model using our favorite IoC container;
[assembly: InterceptTypeLoad( AttributeTargetTypes = "*.Presentation.*View" )]
Now we can leverage the Silverlight built-in navigation services without any pain and much more important without any friction.If you want to give it a try you can simply use nuget to grab a reference to Radical.Extensions.Aspects that now supports also Silverlight 5.
.m