1

I have a ViewModelLocator class that I am defining in app.xaml which is used by my views to databind to the correct ViewModel.

DataContext="{Binding HomeViewModel, Source={StaticResource Locator}}"

I am using Prism and Unity and my ViewModelLocator class needs a reference to an application level unity container.

I wanted inject the IUnityContainer into the ctor of the ViewModelLocator but the ViewModelLocator gets instanciated from app.xaml using a parameterless ctor.

Is there a preferred way to get access to an application level container - for all other classes in the app I just use ctor injection to get the global container.

What I am currenlty doing for the ViewModelLocator is defining a static variable in my BootStrapper class to store the container. I create the container by overriding the CreateContainer method on UnityBootStrapper.

protected override IUnityContainer CreateContainer()
{
    BootStrapper.DIContainer = base.CreateContainer();
    return BootStrapper.DIContainer;
}

Then in the ViewModelLocator class I just reference the BootStrapper.DIContainer property to register my viewmodels

BootStrapper.DIContainer.RegisterType<IShellViewModel, DesignShellViewModel>();

This works fine but it is the only place in the application that needs to reference this static property on the bootstrapper - and would like to get rid of it if possible.

thanks Michael

MIantosca
  • 833
  • 1
  • 10
  • 33

2 Answers2

1

I had the same issue while converting a Silverlight RIA Business app of mine to use Prism, Unity, and MVVM light toolkit. I came up with this workaround which is to just let the App.xaml create an instance of my ViewModelLocator class and during the application startup event I remove that instance it created from the application resources and re-add an instance using Unity container's Resolve method.

  1. Register the VML with Unity.

Boostrapper.cs: (UnityBootstrapper class)

protected override void ConfigureContainer()
{
    Container.RegisterType<ViewModelLocator>(new ContainerControlledLifetimeManager());
    base.ConfigureContainer();
}
  1. Use either constructor or property injection in the VML for IUnityContainer. Here I'm using property injection. Also note that the default parameterless constructor is required because App.xaml is going to instantiate its own instance that we'll just wind up throwing away.

ViewModelLocator.cs: (used for blendability)

public class ViewModelLocator
{
    [Dependency]
    public IUnityContainer Container { get; set; }

    public ViewModelLocator() { }

....

}

  1. Remove and re-add the VML to the application resources. Replace the string literal "Locator" with whatever you called your VML in the App.xaml ResourceDictionary section.

App.xaml.cs:

private void Application_Startup(object sender, StartupEventArgs e)
{
    Bootstrapper bootstrapper = new Bootstrapper();
    bootstrapper.Run();

    Resources.Remove("Locator");
    Resources.Add("Locator", bootstrapper.Container.Resolve<ViewModelLocator>());
}

Your now cocked, locked, and ready to rock..

cadrell0
  • 17,109
  • 5
  • 51
  • 69
TugboatCaptain
  • 4,150
  • 3
  • 47
  • 79
0

I thought I'd follow-up on this since it hasn't been marked as answered.

I've followed a similar approach to Degree451 except I don't remove and re-add the locator as that smells a bit. Instead, I use the built-in capabilities of both Silverlight as well as Unity to handle the problem.

Having the Container property in the ViewModelLocator class marked with the DependencyAttribute means that the class can have its dependencies resolved after instantiation. So in my Bootstrapper, I override ConfigureContainer and add the following code:

var vml = Application.Current.Resources["ViewModelLocator"] as ViewModelLocator;

Container.BuildUp(typeof(ViewModelLocator), vml);

The first line retrieves the instance automatically created by the application from the App.xaml markup. The second line uses Unity to resolve any properties marked with the DependencyAttribute.

To me, this is a much cleaner solution. Of course, it's not Blendable.

SonOfPirate
  • 5,642
  • 3
  • 41
  • 97