Keeping the DI-container usage in the composition root in Silverlight and MVVM
- by adrian hara
It's not quite clear to me how I can design so I keep the reference to the DI-container in the composition root for a Silverlight + MVVM application.
I have the following simple usage scenario: there's a main view (perhaps a list of items) and an action to open an edit view for one single item. So the main view has to create and show the edit view when the user takes the action (e.g. clicks some button).
For this I have the following code:
public interface IView
{
IViewModel ViewModel {get; set;}
}
Then, for each view that I need to be able to create I have an abstract factory, like so
public interface ISomeViewFactory
{
IView CreateView();
}
This factory is then declared a dependency of the "parent" view model, like so:
public class SomeParentViewModel
{
public SomeParentViewModel(ISomeViewFactory viewFactory)
{
// store it
}
private void OnSomeUserAction()
{
IView view = viewFactory.CreateView();
dialogService.ShowDialog(view);
}
}
So all is well until here, no DI-container in sight :). Now comes the implementation of ISomeViewFactory:
public class SomeViewFactory : ISomeViewFactory
{
public IView CreateView()
{
IView view = new SomeView();
view.ViewModel = ????
}
}
The "????" part is my problem, because the view model for the view needs to be resolved from the DI-container so it gets its dependencies injected. What I don't know is how I can do this without having a dependency to the DI-container anywhere except the composition root.
One possible solution would be to have either a dependency on the view model that gets injected into the factory, like so:
public class SomeViewFactory : ISomeViewFactory
{
public SomeViewFactory(ISomeViewModel viewModel)
{
// store it
}
public IView CreateView()
{
IView view = new SomeView();
view.ViewModel = viewModel;
}
}
While this works, it has the problem that since the whole object graph is wired up "statically" (i.e. the "parent" view model will get an instance of SomeViewFactory, which will get an instance of SomeViewModel, and these will live as long as the "parent" view model lives), the injected view model implementation is stateful and if the user opens the child view twice, the second time the view model will be the same instance and have the state from before. I guess I could work around this with an "Initialize" method or something similar, but it doesn't smell quite right.
Another solution might be to wrap the DI-container and have the factories depend on the wrapper, but it'd still be a DI-container "in disguise" there :)
Any thoughts on this are greatly appreciated. Also, please forgive any mistakes or rule-breaking, since this is my first post on stackoverflow :)
Thanks!
ps: my current solution is that the factories know about the DI-container, and it's only them and the composition root that have this dependency.