Using Windsor Castle Container for Viewmodel Injection

Jul 22, 2014 at 7:25 PM
Hello all,

I'm trying to use mui with the Windsor Castle DI container to inject my viewmodels into mui pages. I figured out a solution which works but I'm not at all sure if this is the way it is supposed to be done. Here is what I did:

In App.xaml.cs I wire up a mapping between the UI Pages and the corresponding viewmodels in the container:
  public partial class App : Application
    {
        protected override void OnStartup(StartupEventArgs e)
        {
            base.OnStartup(e);

            var container = new WindsorContainer();

            // Wire up viewmodels, models etc 
            // 
            // container.Register....
            // ToDo ....
            // ToDo ....
            
            
            // Map Views to Viewmodels
            container.Register(Component.For<Page1>().ImplementedBy(typeof(Page1_Viewmodel)));
            container.Register(Component.For<Page2>().ImplementedBy(typeof(Page2_Viewmodel)));
            
            Resources.Add("My_MUI_Castle_Contentloader", new My_MUI_Castle_Contentloader(container));

            var MainWin = new MainWindow();
            MainWin.Show();
        }
    }

I pass the Windsor container to a custom ContentLoader where I resolve the viewmodels and inject them to the corresponding page.
 public class My_MUI_Castle_Contentloader : DefaultContentLoader
    {
        public My_MUI_Castle_Contentloader(IWindsorContainer container)
        {
            this.container = container;
        }
        private readonly IWindsorContainer container;

        protected override object LoadContent(Uri uri)
        {
            var content = base.LoadContent(uri);

            var page = content as FrameworkElement; 
            if (page != null)
            {                
                page.DataContext = container.Resolve(page.GetType());
            }
            return content;
        }
    }
The ContentLoader is then used by MainWindow to load the pages.

The code does what it is supposed to do but I think that passing the container around is not the correct way to implement a DI Container.

Any better idea for implementing Dependency Injection with mui?

Thanks a lot
Lutz
Jul 22, 2014 at 7:48 PM
What you are doing is exactly the same I tried at first, the only difference was, that I was using Unity container. In my opinion, the default mui way is good for small projects. If projects are larger, the mui styles and templates are still great, but its navigation may need some tweaks. I already had the full journey you are obviously starting right now. I am not sure, if it fits your needs, but you can find my latest sample (MUI, Unity and PRISM) as well as related discussion here.
Jul 23, 2014 at 8:51 PM
Edited Jul 23, 2014 at 8:55 PM
Thanks for sharing your code. I had a look at it but I have to admit that your solution is some orders of magnitude too complex for me to understand. As you already mentioned I'm just starting this interesting 'dependency injection journey'. Thus, I currently try to keep things as simple as possible until I become more fluent in the pattern.

Here a (hopefully) improved approach to the problem of injecting viewmodels to m:ui Pages:
Instead of passing the DI container to the content loader I now inject a list of all registered viewmodels (identified by the marker interface "IPageViewmodel") to it. Afterwards I map the Pages to the corresponding viewmodels and inject the content loader to the main window.
  public partial class App : Application
    {
        protected override void OnStartup(StartupEventArgs e)
        {
            base.OnStartup(e);

            var container = new WindsorContainer();
            container.Kernel.Resolver.AddSubResolver(new CollectionResolver(container.Kernel,true));
                        
            // Wire up viewmodels, models etc 
            // 
            // container.Register....
            // ToDo ....
                     
            // Register all Page Viewmodels identified by the marker interface "IPageViewmodel"
            container.Register(Classes.FromAssemblyContaining<IPageViewmodel>().BasedOn<IPageViewmodel>().WithServiceBase());

            // Register the Custom Contentloader            
            container.Register(Component.For<My_MUI_Castle_Contentloader>());

            // The loader depends on IEnumerable<IPageViewmodel>
            // -> this call will resolve all registered viewmodels
            var ContentLoader = container.Resolve<My_MUI_Castle_Contentloader>(); 
            
            // Define the mapping betwen pages and corresponding viewmodels
            ContentLoader.Map<Page1, IPage1Viewmodel>();
            ContentLoader.Map<Page2, IPage2Viewmodel>(); 

            new MainWindow(ContentLoader).Show();                        
        }
    }
Custom Content Loader:
 public class My_MUI_Castle_Contentloader : DefaultContentLoader
    {
        public My_MUI_Castle_Contentloader(IEnumerable<IPageViewmodel> viewmodels)
        {
            this.Viewmodels = viewmodels;
        }

        public void Map<Page, Viewmodel>()
        {
            Mapper.Add(typeof(Page), Viewmodels.OfType<Viewmodel>().First());
        }

        protected override object LoadContent(Uri uri)
        {
            var content = base.LoadContent(uri);

            var Page = content as FrameworkElement;
            if (Page != null)
            {                
                Page.DataContext = Mapper[Page.GetType()];
            }
            return content; 
        }

        private readonly IEnumerable<IPageViewmodel> Viewmodels;
        private Dictionary<Type, object> Mapper = new Dictionary<Type, object>();
    }
I'd be happy for any feedback and improvement ideas.