Currently NoMvvm supports two IoC containers: MEF (comes with .Net 4) and TinyIoC.

In NoMvvm, all you have to do to implement your own container, is implement the IAdapter interface. Thus if you decide you want to use Castle Windsor, it should be relatively easy to hook it up within NoMvvm. Side note: please contribute if you implement an IAdapter!

Let's look at TinyIoC's current implementation, which is relatively simple:

    /// <summary>
    /// An IAdapter wrapping a TinyIoC container for NoMvvm
    /// </summary>
    public sealed class Adapter : IAdapter
    {
        private readonly TinyIoCContainer _container;
        private readonly Dictionary<Type, string> _viewLookup = new Dictionary<Type, string>();

        /// <summary>
        /// Default ctor, requires a TinyIoCContainer
        /// </summary>
        /// <param name="container"></param>
        public Adapter(TinyIoCContainer container)
        {
            _container = container;
        }

        /// <summary>
        /// Gets an exported value of type T
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public T Get<T>()
             where T : class
        {
            return _container.Resolve<T>();
        }

        /// <summary>
        /// Gets an exported value by export name
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public dynamic Get(string name)
        {
            return _container.Resolve(typeof(object), name);
        }

        /// <summary>
        /// Gets a list of exported values of type T
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public IEnumerable<T> GetMany<T>()
             where T : class
        {
            return _container.ResolveAll<T>();
        }

        /// <summary>
        /// Gets a list of exported values by export name
        /// NOTE: TinyIoC does not support this operation
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public IEnumerable<dynamic> GetMany(string name)
        {
            throw new NotSupportedException("TinyIoC does not support this operation!");
        }

        /// <summary>
        /// Gets a View of the specified name
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public dynamic GetView(string name)
        {
            return Get(name + Constants.View);
        }

        /// <summary>
        /// Gets a ViewModel of the specified name
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public dynamic GetViewModel(string name)
        {
            return Get(name + Constants.ViewModel);
        }

        /// <summary>
        /// Gets the View for specified ViewModel
        /// </summary>
        /// <param name="viewModel"></param>
        /// <returns></returns>
        public dynamic GetViewFor(dynamic viewModel)
        {
            string name;
            if (_viewLookup.TryGetValue(viewModel.GetType(), out name))
            {
                return GetView(name);
            }

            //TODO: better error info here
            throw new Exception("View not found!");
        }

        /// <summary>
        /// Registers a View/ViewModel pair with the TinyIoC container
        /// </summary>
        /// <param name="name"></param>
        /// <param name="viewType"></param>
        /// <param name="viewModelType"></param>
        /// <returns></returns>
        public IAdapter AddView(string name, Type viewType, Type viewModelType)
        {
            _container.Register(typeof(object), viewType, name + Constants.View);
            _container.Register(typeof(object), viewModelType, name + Constants.ViewModel);
            _viewLookup[viewModelType] = name;
            return this;
        }
    }

TinyIoC is a pretty full featured IoC container, and is even included within one entire cs file.  So TinyIoC is able to be completely included in NoMvvm.  It has explicit registrations and is very easy to get setup.

Couple things to note:

  • Each container needs to make it's own decision on how to wire up View to ViewModel, hence the GetView/GetViewModel/GetViewFor methods
  • My TinyIoC Adapter follows the explicit approach (like TinyIoC) and merely adds an AddView method for wiring up Views to ViewModels

TinyIoC has an explicit method for wiring up View to ViewModel, while MEF has View and ViewModel attributes.  The IAdapter interface tries to maintain maximum flexibility for whichever container you decide to use.

Down the road, I want to also support convention-based View/ViewModel wiring.  Hopefully this flexibility will keep those changes simple.

Another thing I recommend to setup, are some extension methods to help keep the Runtime configuration easy:

    /// <summary>
    /// Holds extension methods for TinyIoC
    /// </summary>
    public static class Extensions
    {
        /// <summary>
        /// Sets up the NoMvvm Runtime class with TinyIoC
        /// </summary>
        /// <param name="runtime"></param>
        /// <param name="container"></param>
        /// <returns></returns>
        public static Runtime SetupTinyIoC(this Runtime runtime, TinyIoCContainer container)
        {
            return runtime.SetupContainer(new Adapter(container));
        }

        /// <summary>
        /// Sets up the NoMvvm Runtime class with TinyIoC
        /// </summary>
        /// <param name="runtime"></param>
        /// <param name="adapter"></param>
        /// <returns></returns>
        public static Runtime SetupTinyIoC(this Runtime runtime, Adapter adapter)
        {
            return runtime.SetupContainer(adapter);
        }
    }

This allows you to setup an Application with TinyIoC like this:

        protected override void OnStartup(StartupEventArgs e)
        {
            base.OnStartup(e);

            var container = new TinyIoCContainer();
            container.Register<YourModelClass>();

            var adapter = new Adapter(container);
            adapter.AddView("Main", typeof(MainView), typeof(MainViewModel));

            Runtime
                .Initialize()
                .SetupTinyIoC(adapter)
                .Start("Main");
        }

Last edited Aug 24, 2011 at 3:52 AM by jonathanpeppers, version 3

Comments

No comments yet.