Thursday, February 28, 2013

MVVM for Windows Phone Developers–Use it Guys! (Part 3)

In the last part of this series we extended our solution with a PCL library for our models, view-models, and we added a Windows 8 project as well as a testing project for Windows 8.
Preparing our projects to with the right version of MVVM Light

We added a the NuGet package “MVVM LIght libraries only (PCL)”. To install the same binary versions, and the specific platform libraries, we need to add the package to our Windows Phone 8 and our Windows 8 project. The installer will install the base-libraries and the specific libraries for Windows Phone 8 and Windows 8.

TIP: Somehow the portable package is only working, when adding the portable package of “BCL Portability Pack for .NET Framework3, Silverlight 4 and 5, And Windows Phone 7.5”. Just search for “Microsoft BCL” and install the package.
Architecture changes

Through the use of PCL, we have a major change in our architecture. All models, view-models and our DAL-Helpers will be located in our PCL library.
Here is the changed diagram:



You see, that all the parts we need are now located in the PCL library.
Through this architectural change, we need to handle now other problems, that come up with PCL.

We can use a “centralized” view-model-locator, that will help us, to locate our view-models via static-properties, or should we try another approach?

And some other questions that come up like: “How can we manage the data-access in a generic way?”.

Solution


Implement a bootstrapper for MVVM-Light with Ninject


Ok. We have certain types that are implemented by our view-models and model classes. We have also interfaces that are implemented by our units-of-work and our repositories.
This is a very good use-case for dependency injection. We roll up everything bottom-up based on our architecture diagram.

Adding the IUnit of work interface


Expand our MVVMWindowsPhone.Core.Portable (maybe this should be renamed) and right-click the folder DAL. Select “Add new item…” and add a new interface, name it “IUnitOfWork”. Add the following code:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Linq.Expressions;

using System.Text;

 

namespace MVVMWindowsPhone.Core.Portable.DAL

{

    /// <summary>

    /// Unit of work to use as abstraction.

    /// </summary>

    /// <typeparam name="T"></typeparam>

    public interface IUnitOfWork<T> where T:class

    {

              

       /// <summary>

       /// The context to work with

       /// the specific database, file,

       /// whatever.

       /// </summary>

       T Context {get; set;}

       

        /// <summary>

        /// Set the current context.

        /// Since we cannot use constructors

        /// in interfaces.

        /// </summary>

        /// <param name="context"></param>

       void SetContext(T context);              

    }

}


This interface has one property of type T called “Context” this will hold our “Database access object” like a context used for EF or the SQLiteConnection object, to perform actions to our databases. Every platform like Windows 8 or Windows Phone 8 will have it’s own implementation.

The next interface to add is the “IRepository” interface, it will be placed into the DAL folder also:


using System;

using System.Collections.Generic;

using System.Linq;

using System.Linq.Expressions;

using System.Text;

 

namespace MVVMWindowsPhone.Core.Portable.DAL

{

    public interface IRepository<T,U> where T:class where U:class

    {

 

        /// <summary>

        /// The unit of work to use.

        /// Like SQLite, or file driver.

        /// </summary>

        IUnitOfWork<U> Driver {get; set;}

 

        /// <summary>

        /// Get all entries.

        /// </summary>

        /// <returns></returns>

        IQueryable<T> GetAllEntries();

 

        /// <summary>

        /// Get filtered entries.

        /// </summary>

        /// <param name="data"></param>

        /// <param name="filter"></param>

        /// <returns></returns>

        IQueryable<T> GetFilteredEntries(IEnumerable<T> data, Expression<Func<T, bool>> filter);

 

        /// <summary>

        /// DeleteEntry

        /// </summary>

        /// <param name="entry"></param>

        /// <returns></returns>

        T DeleteEntry(T entry);

 

        /// <summary>

        /// Update Entry.

        /// </summary>

        /// <param name="entry"></param>

        /// <param name="updateValue"></param>

        /// <returns></returns>

        T UpdateEntry(T entry, T updateValue);

 

        /// <summary>

        /// Add a new entry.

        /// </summary>

        /// <param name="Entry"></param>

        /// <returns></returns>

        T AddEntry(T Entry);

    }

}


This interface has the following members:


  • IUnitOfWork<U> => Our db access object

  • IQueyable<T> GetAllEntries() => Get all entries from a specific table, of file

  • IQueryable<T> GetFilteredEntries(IEnumeralable<T> data, Expression<Func<T, bool>> filter) => allows us, to filter for specific values using LINQ

  • T DeleteEntry(T Entry) => allows us to delete a specific entry

  • T UpdateEntry(T Entry, T updateValue) => allows us to update a specific entry. This is not commonly used in an IRepository. If we would use EF (EntityFramework) we could ignore this member. But we are using SQLight, which still seems to have problems with atomic database actions.

  • T AddEntry(T Entry) => Add a new entry to a table or file, or whatever we use to save data (like a web-service for example)

Install Ninject for Portable Class Libraries


Ninject is also available for portable class libraries. So right-click the “References” entry in our portable-core project  and choose “Manage NuGet-Packages…”. Type “ninject-portable” into the search-box on the right side and install the entry stating “Ninject for Portable Class Libraries”. That’s it.

NinjectPortable

The bootstrapper based on Ninject


To understand Ninject, and how it basically works, you can visit the Ninject Wiki here:

Ninject-Wiki

However, if you want to learn more about dependency injection using .NET you can buy this book:

Dependency injection in .NET (I don’t know the author, and I am not making any money with that. I love the book)

The base requirements for the bootstrapper are:


  • Localize and create instances of the view-models we use

  • Inject all the interfaces and load the respective types, tied to those interfaces, or hosting the interfaces

  • Create a locator, that enables us to use the view-models in our applications on Windows Phone 8 and Windows 8

Preparing the bootstrapper implementation


We have installed Ninject now, and we have set the base requirements for our bootstrapper.

Now we need to add the base interfaces and classes we will need later in our implementation, these include:

A base view-model, that we can use to inject the required parts we need, like the repository and the unit-of-work

  • Basic service for navigation

  • Basic service to handle application settings

With service interfaces are meant here. This interfaces offer “services” like navigation and settings management. This can be confusing, because the most people think about web-services or similar things when hearing that.

Adding the services


To have everything in place, create a new project-folder inside our portable core project and add two new interfaces:

  • INavigationService

  • ISettingsService

Here is the code for the two files:


using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

 

namespace MVVMWindowsPhone.Core.Portable.Services

{

    /// <summary>

    /// The navigation service to 

    /// enable page navigation.

    /// For all our platforms.

    /// </summary>

    public interface INavigationService

    {

        /// <summary>

        /// Navigate to a specific page.

        /// Used for Windows phone.

        /// </summary>

        /// <param name="page">The absolute uri to the page to navigate to.</param>

        void NavigateTo(Uri page);

 

        /// <summary>

        /// Used for Windows 8.

        /// </summary>

        /// <param name="pageToNavigateTo"></param>

        void NavigateTo(Type pageToNavigateTo);

 

 

        /// <summary>

        /// Go back to

        /// the previous page.

        /// Used for Windows Phone and Windows 8.

        /// </summary>

        void GoBack();

    }

}





We have an overload of the NavigateTo-Method here. The first one is for Windows Phone and the second one is for Windows 8. The GoBack-Method is for both systems. For the sake of simplicity I am not breaking this down into a partial interface or two single interfaces.


using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

 

namespace MVVMWindowsPhone.Core.Portable.Services

{

    /// <summary>

    /// This is our settings

    /// servcie. To save and

    /// load settgins.

    /// </summary>

    public interface ISettingsService

    {

        /// <summary>

        /// Save a setting.

        /// </summary>

        /// <typeparam name="T">The type to save.</typeparam>

        /// <param name="value">The value of T to save.</param>

        /// <param name="key">The key under which to save the value.</param>

        /// <returns></returns>

        bool SaveSetting<T>(T value, string key);

 

        /// <summary>

        /// Load a setting.

        /// </summary>

        /// <typeparam name="T">The type to save.</typeparam>

        /// <param name="value">The value of T to save.</param>

        /// <param name="key">The key under which to save the value.</param>

        /// <returns></returns>  

        T LoadSetting<T>(T value, string key);

 

        /// <summary>

        /// Remove a settings entry 

        /// with a specific key.

        /// </summary>

        /// <param name="key">The key to pin the settings entry to delete.</param>

        /// <returns></returns>

        bool RemoveSetting(string key);

    }

}


This “Service” has three members, where two of it are generic. We will later use those generic methods to serialize complete types on each platform with serialization frameworks.

The base view-model


We are using MVVM-Light here (the portable branch), this means that we want to get all the advantages of MVVM-Light we want to use. The basic view-model class in MVVM-Light is called “ViewModelBase”. This class offers us the following things out of the box:


  • Design-Time mode detection (in the PCL version, for different systems)

  • Messaging

  • PropertyChanged notification (Inheriting from ObservableObject another MVVM-Class that offers various possibilities to raise a property changed notification)

Here is the original ViewModelBase class from the MVVM-Light (the portable version) just to give you a feeling about what it offers (Courtesy of MVVM-Light):


using GalaSoft.MvvmLight.Helpers;

using GalaSoft.MvvmLight.Messaging;

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Linq;

using System.Linq.Expressions;

using System.Reflection;

using System.Runtime.CompilerServices;

 

namespace GalaSoft.MvvmLight

{

    public abstract class ViewModelBase : ObservableObject, ICleanup

    {

        private static bool? _isInDesignMode;

 

        private IMessenger _messengerInstance;

 

        public bool IsInDesignMode

        {

            get

            {

                return ViewModelBase.IsInDesignModeStatic;

            }

        }

 

        public static bool IsInDesignModeStatic

        {

            get

            {

                if (!ViewModelBase._isInDesignMode.HasValue)

                {

                    ViewModelBase._isInDesignMode = new bool?(ViewModelBase.IsInDesignModePortable());

                }

                return ViewModelBase._isInDesignMode.Value;

            }

        }

 

        protected IMessenger MessengerInstance

        {

            get

            {

                IMessenger messenger = this._messengerInstance;

                IMessenger @default = messenger;

                if (messenger == null)

                {

                    @default = Messenger.Default;

                }

                return @default;

            }

            set

            {

                this._messengerInstance = value;

            }

        }

 

        public ViewModelBase() : this(null)

        {

        }

 

        public ViewModelBase(IMessenger messenger)

        {

            this.MessengerInstance = messenger;

        }

 

        protected virtual void Broadcast<T>(T oldValue, T newValue, string propertyName)

        {

            PropertyChangedMessage<T> propertyChangedMessage = new PropertyChangedMessage<T>(this, oldValue, newValue, propertyName);

            this.MessengerInstance.Send<PropertyChangedMessage<T>>(propertyChangedMessage);

        }

 

        public virtual void Cleanup()

        {

            this.MessengerInstance.Unregister(this);

        }

 

        private static bool IsInDesignModeMetro()

        {

            bool value;

            try

            {

                Type type = Type.GetType("Windows.ApplicationModel.DesignMode, Windows, ContentType=WindowsRuntime");

                PropertyInfo property = type.GetProperty("DesignModeEnabled", BindingFlags.Static | BindingFlags.Public);

                value = (bool)property.GetValue(null, null);

            }

            catch

            {

                value = false;

            }

            return value;

        }

 

        private static bool IsInDesignModeNet()

        {

            bool flag;

            try

            {

                Type type = Type.GetType("System.ComponentModel.DesignerProperties, PresentationFramework, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");

                object value = type.GetField("IsInDesignModeProperty", BindingFlags.Static | BindingFlags.Public).GetValue(null);

                Type type1 = Type.GetType("System.ComponentModel.DependencyPropertyDescriptor, WindowsBase, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");

                Type type2 = Type.GetType("System.Windows.FrameworkElement, PresentationFramework, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");

                MethodInfo[] methods = type1.GetMethods(BindingFlags.Static | BindingFlags.Public);

                MethodInfo[] methodInfoArray = methods;

                MethodInfo methodInfo = ((IEnumerable<MethodInfo>)methodInfoArray).Single<MethodInfo>((MethodInfo mi) => {

                    if (mi.Name != "FromProperty")

                    {

                        return false;

                    }

                    else

                    {

                        return (int)mi.GetParameters().Length == 2;

                    }

                });

                object[] objArray = new object[] { value, type2 };

                object obj = methodInfo.Invoke(null, objArray);

                PropertyInfo property = type1.GetProperty("Metadata", BindingFlags.Instance | BindingFlags.Public);

                object value1 = property.GetValue(obj, null);

                Type type3 = Type.GetType("System.Windows.PropertyMetadata, WindowsBase, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");

                PropertyInfo propertyInfo = type3.GetProperty("DefaultValue", BindingFlags.Instance | BindingFlags.Public);

                bool flag1 = (bool)propertyInfo.GetValue(value1, null);

                flag = flag1;

            }

            catch

            {

                flag = false;

            }

            return flag;

        }

 

        private static bool IsInDesignModePortable()

        {

            DesignerPlatformLibrary detectedDesignerLibrary = DesignerLibrary.DetectedDesignerLibrary;

            if (detectedDesignerLibrary != DesignerPlatformLibrary.WinRT)

            {

                if (detectedDesignerLibrary != DesignerPlatformLibrary.Silverlight)

                {

                    if (detectedDesignerLibrary != DesignerPlatformLibrary.Net)

                    {

                        return false;

                    }

                    else

                    {

                        return ViewModelBase.IsInDesignModeNet();

                    }

                }

                else

                {

                    bool flag = ViewModelBase.IsInDesignModeSilverlight();

                    if (!flag)

                    {

                        flag = ViewModelBase.IsInDesignModeNet();

                    }

                    return flag;

                }

            }

            else

            {

                return ViewModelBase.IsInDesignModeMetro();

            }

        }

 

        private static bool IsInDesignModeSilverlight()

        {

            bool value;

            try

            {

                Type type = Type.GetType("System.ComponentModel.DesignerProperties, System.Windows, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e");

                PropertyInfo property = type.GetProperty("IsInDesignTool", BindingFlags.Static | BindingFlags.Public);

                value = (bool)property.GetValue(null, null);

            }

            catch

            {

                value = false;

            }

            return value;

        }

 

        protected virtual void RaisePropertyChanged<T>(string propertyName, T oldValue, T newValue, bool broadcast)

        {

            if (!string.IsNullOrEmpty(propertyName))

            {

                this.RaisePropertyChanged(propertyName);

                if (broadcast)

                {

                    this.Broadcast<T>(oldValue, newValue, propertyName);

                }

                return;

            }

            else

            {

                throw new ArgumentException("This method cannot be called with an empty string", "propertyName");

            }

        }

 

        protected virtual void RaisePropertyChanged<T>(Expression<Func<T>> propertyExpression, T oldValue, T newValue, bool broadcast)

        {

            PropertyChangedEventHandler propertyChangedHandler = base.PropertyChangedHandler;

            if (propertyChangedHandler != null || broadcast)

            {

                string propertyName = base.GetPropertyName<T>(propertyExpression);

                if (propertyChangedHandler != null)

                {

                    propertyChangedHandler(this, new PropertyChangedEventArgs(propertyName));

                }

                if (broadcast)

                {

                    this.Broadcast<T>(oldValue, newValue, propertyName);

                }

            }

        }

 

        protected bool Set<T>(Expression<Func<T>> propertyExpression, ref T field, T newValue, bool broadcast)

        {

            if (!EqualityComparer<T>.Default.Equals(field, newValue))

            {

                this.RaisePropertyChanging<T>(propertyExpression);

                T t = field;

                field = newValue;

                this.RaisePropertyChanged<T>(propertyExpression, t, field, broadcast);

                return true;

            }

            else

            {

                return false;

            }

        }

 

        protected bool Set<T>(string propertyName, ref T field, T newValue, bool broadcast)

        {

            if (!EqualityComparer<T>.Default.Equals(field, newValue))

            {

                this.RaisePropertyChanging(propertyName);

                T t = field;

                field = newValue;

                this.RaisePropertyChanged<T>(propertyName, t, field, broadcast);

                return true;

            }

            else

            {

                return false;

            }

        }

    }

}

 


 

Add a new class to the folder “ViewModel” (in our portable core project) we added it  in the last part before and name it “BaseViewModel.cs”. We will inherit from “ViewModelBase” and add some additional features we need for our sample:

 


using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using GalaSoft.MvvmLight;

using MVVMWindowsPhone.Core.Portable.DAL;

using System.Collections.ObjectModel;

using MVVMWindowsPhone.Core.Portable.Services;

using Ninject;

 

namespace MVVMWindowsPhone.Core.Portable.ViewModel

{

    /// <summary>

    /// Our base-view model

    /// based on the ViewModelBase

    /// of MVVM-Light portable, with

    /// two generic type parameters

    /// to support our IRepository.

    /// </summary>

    /// <typeparam name="T"></typeparam>

    /// <typeparam name="U"></typeparam>

    public class BaseViewModel<T,U>:ViewModelBase where U:class where T:class

    {

 

        /// <summary>

        /// The data we need for our ViewModel.

        /// </summary>

        private  ObservableCollection<T> data;

 

        /// <summary>

        /// Our navigation service we need.

        /// </summary>

        private readonly  INavigationService navigationService;

 

        /// <summary>

        /// The data we need for our ViewModel.

        /// </summary>

        public  ObservableCollection<T> Data

        {

            get { return data; }

            set { data = value; }

        }

 

        /// <summary>

        /// The repository we use.

        /// </summary>

        private readonly IRepository<T,U> repository;

 

        /// <summary>

        /// Our constructor.

        /// This one will be used

        /// to inject our repository.

        /// </summary>

        /// <param name="repo"></param>

        [Inject]

        public BaseViewModel(IRepository<T,U> repo,INavigationService navService)

        {

            this.repository = repo;

            this.navigationService = navService;

            this.Model = new ObservableCollection<T>();

        }

                

    }

}


We inherit from the “ViewModelBase” class and add two generic type parameters T,U. Where T stands for the type of our current model-class we want to use and U stands for the current unit-of-work we want to use. The injection-technique we use here is constructor-injection. You can see the “[Injection]” attribute placed on the constructor of our “BaseViewModel”.

We have the following members in our BaseViewModel:


  • Data => This is our main collection that will contain our entries, based on the type for our model we pass through the generic parameter U

  • navigationService => Here we pass an instance of the INavigationService interface. This will be done through constructor injection utilizing Ninject

  • repository => this is the IRepository implementation that we will inject into our view-model through constructor injection

The View-Model-Locator


The VML (View-Model-Locator) is responsible to deliver the view-models for our view. The current implementation of the VML is quite different from the standard VML of MVVM-Light:


using GalaSoft.MvvmLight;

using MVVMWindowsPhone.Core.Portable.Bootstrapper;

using MVVMWindowsPhone.Core.Portable.DAL;

using MVVMWindowsPhone.Core.Portable.Services;

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Runtime.CompilerServices;

 

namespace MVVMWindowsPhone.Core.Portable.ViewModel

{

    /// <summary>

    /// The ViewModel locator.

    /// </summary>

    public class ViewModelLocator:IViewModelLocator

    {

        /// <summary>

        /// Our view models.

        /// </summary>

        Dictionary<string, ViewModelBase> viewModels;

 

        /// <summary>

        /// Our view models.

        /// </summary>

        public Dictionary<string, ViewModelBase> ViewModels

        {

            get { return viewModels; }

            set { viewModels = value; }

        }

        

        /// <summary>

        /// Standard constructor.

        /// </summary>

        public ViewModelLocator()

        {

            

            ViewModels = new Dictionary<string,ViewModelBase>();

                       

        }

        

        /// <summary>

        /// Set and get your ViewModels

        /// here.

        /// </summary>

        /// <param name="viewModelName">The name of the viewmodel to get or set.</param>

        /// <returns>The viewmodel selected.</returns>

        public dynamic this[string viewModelName]

        {

            get

            {

                if(ViewModels.ContainsKey(viewModelName))

                {

                    return this.ViewModels[viewModelName];

                }

                else

                {

                    return null;  

                }

            }

           

        }

        

    }

 

}


Because of the generic implementation of the BaseViewModel-class, I came up with the indexer of type dynamic. You can see that there is a Dictionary<string,ViewModelBase> defined. Our BaseViewModel-class has two generic type parameters, that can be reference types of any kind. Therefore creating a VML with those type parameters would allow us only to host view-models of a certain type, and that’s not what is the goal here. Therefore the dictionary “ViewModels” contain the base type “ViewModelBase”. The indexer is of type dynamic. Therefore getting a property from our ViewModel will be resolved dynamically at runtime.

And here is the corresponding interface “IViewModelLocator” used later for injection:


using System;

using System.Collections.Generic;

using GalaSoft.MvvmLight;

 

namespace MVVMWindowsPhone.Core.Portable.Bootstrapping

{

    /// <summary>

    /// The base for our Viewmodel locator.

    /// </summary>

    interface IViewModelLocator

    {

        /// <summary>

        /// The indexer to get the 

        /// right ViewModel.

        /// </summary>

        /// <param name="viewModelName"></param>

        /// <returns></returns>

        dynamic this[string viewModelName] { get; }

 

        /// <summary>

        /// The dictionary to 

        /// save the ViewModels to.

        /// </summary>

        Dictionary<string, ViewModelBase> ViewModels { get; set; }

    }

}


The bootstrapper


Through the basic structure of PCL projects, supporting different platforms, we move to the direction of abstracting as much as possible of our portable core by using interfaces and abstract classes.

The next thing to do, is to install the respective components for Ninject in our Windows 8 and Windows Phone 8 projects. Fire up the NuGet reference dialog  and install the portable version of Ninject in both projects. This will add some platform-specific assemblies to each of the platforms. Check the reference folder after installing the assemblies.

NinjectReferencesWin8WP8

This should give you (and hopefully me, too, once and forever) the hint, how all the PCL stuff works:

  • Add a base component like the Ninject portable that can be understood by the chosen platforms configured for the PCL library

  • Add the abstractions like interfaces, abstract classes to the PCL library, to be used for every single platform

  • Add the specific platform dependencies to your chosen platforms like Win8, WP8, what ever you chose

  • Add an entry point (a method) to new-up the needed classes to make that stuff run

The current implementation for the basic bootstapper, requires to add two new files to our PCL project:


  • IBootStrapper.cs => The base interface for our bootstrapper

  • SimpleBootstrapper.cs (an abstract class to be implemented later in WP8 and Win8)

As always, you can name the files to whatever you prefer. Here is the source:


using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using Ninject;

using Ninject.Modules;

using MVVMWindowsPhone.Core.Portable.Bootstrapping;

 

namespace MVVMWindowsPhone.Core.Portable.Bootstrapper

{

    /// <summary>

    /// Defines the basics for our

    /// simple bootstrapper.

    /// </summary>

    public interface IBootstrapper

    {

        /// <summary>

        /// The Ninject kernel we 

        /// need to load what needs

        /// to be injected.

        /// </summary>

        IKernel Container {get;set;}

 

        /// <summary>

        /// The ViewModel-Locator

        /// we need later for data-binding.

        /// </summary>

        IViewModelLocator ViewModelLocator {get;set;}

 

        /// <summary>

        /// The Ninject modules to load.

        /// </summary>

        IList<INinjectModule> Modules {get;set;}

 

        /// <summary>

        /// Configure the "parts"

        /// we want to use in

        /// our project.

        /// </summary>

        void ConfigureBootstrapper();

 

    }

}







This interface has the following members:


  • Container of type IKernel => the Ninject kernel we will use later

  • ViewModelLocator of type IViewModelLocator => We will use this one later to “load” our view-models via Ninject

  • Modules of type IList<INinjectModule> => our Ninject modules will be “loaded” into this member

And here is the abstract class we use later to derive from in our WP8 and Win8 projects:


using MVVMWindowsPhone.Core.Portable.Bootstrapper;

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using Ninject;

using Ninject.Modules;

 

 

namespace MVVMWindowsPhone.Core.Portable.Bootstrapping

{

    /// <summary>

    /// This is a simple implementation of our

    /// bootstrapper for Ninject. This needs to 

    /// be

    /// </summary>

    public abstract class SimpleBootstrapper:IBootstrapper

    {

        

        /// <summary>

        /// The Ninject-Kernel,

        /// our Container in terms

        /// of 

        /// </summary>

        private IKernel container;

 

        /// <summary>

        /// The list of modules to import.

        /// </summary>

        private IList<INinjectModule> modules;

 

        /// <summary>

        /// 

        /// </summary>

        private IViewModelLocator viewModelLocator;

 

        /// <summary>

        /// The container (Ninject Kernel)

        /// used to bind the types to

        /// the interfaces.

        /// </summary>

        public IKernel Container

        {

            get

            {

                return this.container;

            }

            set

            {

                this.container = value;

            }

        }

 

        /// <summary>

        /// The ninject modules

        /// to be loaded by the 

        /// container (Ninject Kernel)

        /// </summary>

        public IList<INinjectModule> Modules

        {

            get

            {

                return this.modules;

            }

            set

            {

                this.modules = value;

            }

        }

 

        /// <summary>

        /// The ViewModel-Locator

        /// that holds the instantiated

        /// ViewModels to bind the

        /// XAML against.

        /// </summary>

        public IViewModelLocator ViewModelLocator

        {

            get

            {

                return this.viewModelLocator;

            }

            set

            {

                this.viewModelLocator = value;

            }

        }

 

        /// <summary>

        /// The standard constructor.

        /// </summary>

        public SimpleBootstrapper()

        {

           //Nothing here curretnly.

        }

 

        /// <summary>

        /// This method is defined

        /// as virtual, to enable

        /// an entry point for Ninject

        /// like stated by Owen on Twitter.

        /// </summary>

        public virtual void ConfigureBootstrapper()

        {

           //Not implemented yet.

        }

 

     

    }

}


We will use the ConfigureBootstrapper-Method later, to configure and setup everything we need to work successfully with Ninject.

In the next part, I show you how to put all this stuff together.

Thank you for reading. If you have ideas, or want to see something additional here, let me know. All the code is hosted on GitHub: https://github.com/Injac/WindowsPhone8MVVM