DependencyInjection on Opening a Window

Topics: Bootstrappers & IoC, Getting Started, UI Architecture
Feb 12, 2014 at 6:06 PM
Hey guys!

So, I use StructureMap's dependency injection with Caliburn.Micro. All of my ViewModels incorporate DI in the constructor arguments. I'm now at the point where I need to open, close, and hide windows (Probably by passing along IAppWindowManager (which inherits from IWindowManager).

Unfortunately, what I'm stuck at is resolving an instantiation of the view and view model with dependency injection using the container defined in my bootstrapper. So far, this is what I have.
    public class AppWindowManager
        : WindowManager, IAppWindowManager
    {
        private readonly IDictionary<Type, Window> _windows
            = new Dictionary<Type, Window>();

        public void Open<T>()
        {
            var window 
                = _windows.Any(d => d.Key 
                    == typeof(T));
            if (window)
            {
                _windows.SingleOrDefault(d => d.Key 
                    == typeof(T)).Value.Show();
                return;
            }

            // Create window
            //_windows.Add(typeof(T),
            //    CreateWindow(T, false, null, null)); <-- Erk?
        }

        public void Close<T>()
        {
            var window
                = _windows.Any(d => d.Key
                    == typeof(T));
            if (!window)
                throw new ArgumentNullException();

            // Delete window
            //_windows.SingleOrDefault(d => d.Key
            //        == typeof(T)).Value.Close(); <-- Also erk!
            _windows.Remove(typeof(T));
        }

        public override void ShowWindow(object rootModel,
            object context = null, IDictionary<string, object> settings = null) {
            var navigationWindow = (NavigationWindow)null;
            if (Application.Current != null && Application.Current.MainWindow != null)
                navigationWindow = Application.Current.MainWindow as NavigationWindow;
            if (navigationWindow != null) {
                var page = CreatePage(rootModel, context, settings);
                navigationWindow.Navigate(page);
            } else
            {
                if (rootModel.GetType() == typeof(TrayIconViewModel))
                    CreateWindow(rootModel, false, context, settings);
                else
                    CreateWindow(rootModel, false, context, settings).Show();
            }
        }
    }
And
public class AppBootstrapper
        : BootstrapperBase
    {
        private IContainer _container;

        public AppBootstrapper()
        {
            Start();
        }

        protected override void Configure()
        {
            _container 
                = IoC.Initialize();
        }

        protected override object GetInstance(Type serviceType, string key)
        {
            object service;
            if (!serviceType.IsAbstract 
                && !serviceType.IsInterface 
                && serviceType.IsClass) {
                // Concrete type resolution
                service = _container.GetInstance(serviceType);
            } else {
                // Other type resolution.
                service = _container.TryGetInstance(serviceType) ?? base.GetInstance(serviceType, key);
            }
            return service;
        }

        protected override IEnumerable<object> GetAllInstances(Type serviceType) {
            return _container.GetAllInstances(serviceType).Cast<object>();
        }

        protected override void OnStartup(object sender, StartupEventArgs e) {
            DisplayRootViewFor<TrayIconViewModel>();
        }
    }
One possible resolution I can think of is passing the container into the IAppWindowManager, but I think that has some code smell. I'm also not sure if that would work, given the class is hooked up while the container is being made. Am I perhaps using the wrong class to control and instantiate windows? I couldn't find much documentation on the WindowConductor, and I'm not sure if that's better suited to what I'm trying to do.

Thanks for the help!