Quantcast
Channel: My musings on .Net Technology » Uncategorized
Viewing all articles
Browse latest Browse all 17

Doing view-model first approach with Caliburn-Micro and Unity, the right way

$
0
0

The following blog post is on caliburn micro which is an MVVM framework (please feel free to skip if you do not use this framework)

When working with Caliburn Micro, I see most people mix and match between view-first and view-model first approach.

The simplest way to ensure that you use the right paradigm and not a mix between the two approach (i.e. view-first or view-model first approach) is to remove ”*.xaml.cs” if you follow a view-model first approach, otherwise keep “.xaml.cs” for a view first approach (in some cases you might want to mix and match, but then it should be an explicit choice).

Caliburn’s preferred approach is to go with view-model first i.e. instantiate viewmodel and let caliburn find the respective view, initialize the view and bind the view-model and view together.

As an example in this demo project, I want to show a window with two panes as below, where each pane is a custom user control.

LeftRightPanes

As we are following a view-model first approach, we will remove all .xaml.cs files and our project structure will be something as below

NoXamlCS

Where ShellView is the root view which host the two panels (I am mixing panels and panes, sorry)

ViewsDeclaration
On running the project at this stage, we will only see the root window with no panes (basically an empty window), this is because when the ShellView’s view is initialized (via caliburn micro), the sub view’s namely “LeftPanelView” and “RightPanelView” view will not be initialized (as we have removed the .xaml.cs containing “InitializeComponent()” call), the two panels will therefore appear blank.

If we had not removed “.xaml.cs” files then we would get the sub-views (left and right panels) initialized, but then we are loading the sub-views first without instantiating respective sub-view-models, not only we are doing it wrong, caliburn would have nothing to bind the view to .

This is the important aspect that we need to understand, when going for a pure view model first approach, we as a developer only need to initialize and care about view model initialization and let the framework care about finding and binding the respective view, if our app is instantiating the view before the view model then it is not a view-model first approach per se.

With caliburn the way we go about from here is to replace the direct references to the user control with “ContentControl” (Caliburn understand the ContentControl tag and resolves and bind with the view as required). To give hint to caliburn we use naming convention attributes.

ContentControlXaml

The corresponding view model would then look as

ShellViewModel

With the above approach, when the ShellViewModel is instantiated, the sub-view’s view-model are also instantiated and caliburn would take care of  finding the view, initializing the control and binding the contentcontrol with respective view model. Everything is hunky dory here … well not, really.

The problem with this approach is that the ShellViewModel should not construct the view-model for the two sub views (it should not be it’s responsibility, shell view model is just a hosting view model).

A better way would be to let a controller create the view models for the two sub views and inject it to the hosting shell view model. But injection does not comes out of the box, if we inject the two sub view models to ShellViewModel, caliburn will shout as below

UpdatedConstructor

NoParameters

This is because caliburn does not use IOC container to resolve the dependencies and looks for empty constructor.

But with great power comes great responsibility, Caliburn allows us to override bootstrapper delegates and thus gives us control how we resolve dependencies and do Dependency Injection.

In the below example I have used Unity container for DI, to suggest caliburn how to resolve dependencies we override the caliburn boostrapper functors and point to Unity to help instantiate and resolve dependencies; thus when the shell view model is instantiated, unity would injected with the two sub view models, and from there caliburn would do the needful the binding.

bootstrapper

This is a much cleaner way of doing a true view-model first approach.



Viewing all articles
Browse latest Browse all 17

Trending Articles