7
votes

I really hope this is not a stupid question, but I'm somehow unable to recognize a straight-forward way to inject dependencies into view models using Caliburn.Micro.

I'm having a main shell (conductor) like so:

public class ShellViewModel : Conductor<IScreen>.Collection.OneActive, IShell
{
    public ShellViewModel(IEventAggregator eventAggregator) {
        ActivateItem(new DashboardViewModel());
    }
}

Now I'd like to inject a service into the DashboardViewModel but since the ActivateItem method requires me to pass an instance (rather than e.g. a type), I'm forced to provide the service myself. And since the ShellViewModel isn't aware of an underlying IoC container, I have to have the service injected into the shell.. to me, it looks like Caliburn is trying to enforce a complete graph of all view models and dependencies within an application.

I am aware that I could use a static accessor for my inversion of control container, but I really don't like this approach because I'd like to have a single composition root for my application (the bootstrapper) without having the other parts knowing about dependency injection and such.

1
Did you find a way to use ActivateItem using an interface to leverage dependency injection? At the moment, the only way is to pass a viewmodel instance and get services via IoC?Sascha

1 Answers

2
votes

couple of ways to do it dependent completely on your choice of container.

MEF [ImportMany] used in the constructor on the parameter that will do the actual import reference the Hello Screens example

The baked in IoC static class you could use IoC.Get<IDashBoard>() or IoC.GetAll<IDashBoard>(), this assumes you have register your types into the container you use. Caution with this one it can be over used and result in anti-pattern behavior. I have done this in one of my apps that does a dashboard, anything that is tagged with IDashBoard in my Container instance, in association with the actual implementation class will get pulled into the collection IoC.GetAll<IDashboard>() or the first item in the collection based on the IoC.Get<IDashBoard>().

You could also make your dashboard inherit Conductor<IDashBoard>.Collection.AllActive, there by allowing you access to the Items property (as part of the Collection) and populate it with the CTOR of your DashBoardViewMode, using IoC.GetAll<IDashboard>() in that one place get all the items you need on your dashboard. From there, I query the Items collection property in OnActivate and match the other viewmodels to the properties that I needed and placed named ContentControls on the DashBoardView accordingly.

this does pull from the container that you have chosen, keeping that in mind you might just want to you the containers' methods to grab the necessary items through its intended design.

I actually moved away from MEF since version used in CM doesn't work with Open Generics and debugging missing Export() attributes was starting to wear me out.