Partager via


Update to MobileMVC with Container

I've recently made a substantial update to the MobileMVC framework. I've added the ability to utilize a (D)epenendcy (I)njection container by adding IControllerProvider interface into the framework which looks like this:

public interface IControllerProvider

{

    Controller GetController(string name);

     Controller GetController(Type type);

     Controller GetController<T>();

     Controller GetController<T>(IView view);

     void RegisterController(Controller controller);

}

This interface gets used in the new class Navigator which could be used instead of NavigationService to navigate between the controllers since it implements the same methods such as Navigate, GoBack, GoForward etc... The Navigator class is exposed as a singleton via the property in the Controller class:

/// <summary>

/// Gets an instance of the Navigator.

/// </summary>

public Navigator Navigator

{

     get

     {

         return Navigator.Current;

     }

}

The Navigator class also includes the following static method:

/// <summary>

/// Sets the IControllerProvider to use.

/// </summary>

/// <param name="controllerProvider"></param>

public static void SetControllerProvider(IControllerProvider controllerProvider)

{

     if (navigator == null)

     {

           navigator = new Navigator(controllerProvider);

     }

}

As you can see the SetControllerProvider method accepts as a parameter an instance of the IControllerProvider which you will need call when your application is initialized.

Before diving into the full usage sample let's talk about the DI container. As we know, there's not much of the DI and IoC containers exist for .NET CF right now, however Paterns & Practices team has been quetly working on the update of the Mobile Application Blocks that where released a few years back. P&P has recently posted a Community Drop of the code refresh for the Mobility Block on the Codeplex and it includes the new block which is called ContainerModel. P&P has decided to utilize the Funq container that was developed by Daniel Cazzulino. So, I've taken this container and updated the sample for the MobileMVC to make a use of it. 

Let's continue on the sample of how you can utilize the new features in the MobileMVC framework. I have modified the existing sample MVCDemoClient (a part of the download of the framework), so let's see how we'd initialize container with the views and controllers:

  private static void Initialize()

  {

       container = new Container();

       // Register Login view and controller

  container.Register<LoginForm>(c => new LoginForm());

       container.Register<LoginController>(c =>

                           new LoginController(c.Resolve<LoginForm>()))

                .InitializedBy((c, v) => v.Container = c);

       // Register Search view and controller

      container.Register<SearchForm>(c => new SearchForm());

            container.Register<SearchController>(c =>

                         new SearchController(c.Resolve<SearchForm>()))

                .InitializedBy((c, v) => v.Container = c);

       // Register Search view and controller

       container.Register<DetailForm>(c => new DetailForm());

   container.Register<DetailController>(c =>

                         new DetailController(c.Resolve<DetailForm>()))

                .InitializedBy((c, v) => v.Container = c);

       // Register data model

       container.Register<Products>(c => new Products());

       // Set ControllerProvider

       Navigator.SetControllerProvider(new ControllerProvider(container));

  }

In the code above when we register a controller, you can see that we call: .InitializedBy((c, v) => v.Container = c) . This means that when an instance of the controller will be created we want to assign the same instance of the container to the Container property which I've added to the controller. We also make a call to the SetControllerProvider method and passing and instance of the ControllerProvider class which as you can guess implements IControllerProvider interface and makes use of the Container:

public class ControllerProvider : IControllerProvider

{

        private Container container;

       

        public ControllerProvider(Container container)

        {

            this.container = container;

        }

      

        #region IControllerProvider Members

        public Controller GetController<T>()

        {

            return this.container.Resolve<T>() as Controller;

        }

        public Controller GetController<T>(IView view)

        {

            Controller controller = this.container.Resolve<Controller>();

            controller.View = view;

            return controller;

        }

        // … Other methods ommitted for brevity

        #endregion

 }

After this short preparation we can now modifiy our code to use the Navigator class. This is how we can show the SearchForm from the LoginController:

private void ShowSearchView()

{

    //SearchController controller = new SearchController(new SearchForm());

    //NavigationService.Navigate(controller);

    this.Navigator.Navigate<SearchController>();

}

Ability to access the Container from the controller is also giving us much more separation from the Data Model or other services that you may use in the application. For example this is how we can get access to the Products data model in the SearchController:

// ViewLoaded event from the view

private void OnViewLoaded(object sender, EventArgs e)

{

      // Show busy cursor

      Cursor.Current = Cursors.WaitCursor;

      // Get an instance from the container

      Products products = this.Container.Resolve<Products>();

      // Populate data

      products.PopulateList();

      // Assign the Model

      this.view.ViewData.Model = products;

  // Notify the view of the changes

    this.NotifyView();

      // Restore the cursor

      Cursor.Current = Cursors.Default;

 }

Overall, I think the usage of the container with the MVC pattern gives you much more flexibility when designing your applications. It allows you to decouple the access to the application services giving you more room during the unit testing as well as making changes to the application without breaking too many dependencies.

You can find the updated version of the MobileMVC framework and the sample in the downloads section of the codeplex project:

https://mobilemvc.codeplex.com/Release/ProjectReleases.aspx?ReleaseId=26507

Comments

  • Anonymous
    May 15, 2009
    Nicely done, Alex, pretty simple and straightforward. Just a quick note to your MVCContainer client demo. The program has to navigate (Navigator) to the program entry point controller, before calling Application.Run or it will have 2 entries in the WM memory applet :). I have been using this for the past week, and i can already notice an increase in performance when navigating through views.
  • Gonçalo
  • Anonymous
    May 15, 2009
    Oh, just to say that i added 2 methods to the Navigator. They are GoBackAndInitialize and GoForwardAndInitialize  since GoBack and GoForward don't call Initialize(). Sometimes it can be useful.
  • Gonçalo