TheBlueSky
TheBlueSky

Reputation: 5948

How To: Caliburn.Micro.Autofac and Windows Phone

Is there and example, tutorial or anything that shows how to use Caliburn.Micro.Autofac with Windows Phone?

I created a basic application with Caliburn.Micro only, and that runs fine. Then I decided to use Caliburn.Micro.Autofac, so I derived my Bootstrapper from Caliburn.Micro.Autofac.AutofacBootstrapper and called base.Configure() inside the Bootstrapper Configure() method. Now wen I ran the application I get "The type 'AppBootstrapper' was not found." exception.

Appreciate any help.

Upvotes: 1

Views: 1314

Answers (2)

Mike Eshva
Mike Eshva

Reputation: 1160

I have implemented a proper version (in my opinion) of Caliburn.Micro.Autofac for Windows Phone. You can download it and test project from my blog. The blog post is in Russian but you'll find the link to ZIP file in the top of the post. The code is too big to post here, so please take from the blog. I've send this to David Buksbaum (the author of Caliburn.Micro.Autofac). Hope he will incorporate it into his code base soon.

UPDATE

What is fixed:

  1. Components realizing IPhoneService and INavigationService services must be instantiated before registering in container.
  2. Realized component implementing IPhoneContainer. Without it you can't use Autofac in Caliburn.Micro.

Upvotes: -1

Cameron MacFarland
Cameron MacFarland

Reputation: 71936

This is the bootstrapper I wrote for a WP7 project. It's based on Caliburn.Micro.Autofac.AutofacBootstrapper but fixes some bugs.

public class AppBootstrapper : PhoneBootstrapper
{
    private IContainer container;

    protected void ConfigureContainer(ContainerBuilder builder)
    {
        // put any custom bindings here
    }

    #region Standard Autofac/Caliburn.Micro Bootstrapper

    protected override void Configure()
    {
        //  configure container
        var builder = new ContainerBuilder();

        //  register phone services
        var caliburnAssembly = AssemblySource.Instance.Union(new[] { typeof(IStorageMechanism).Assembly }).ToArray();
        //  register IStorageMechanism implementors
        builder.RegisterAssemblyTypes(caliburnAssembly)
          .Where(type => typeof(IStorageMechanism).IsAssignableFrom(type)
                         && !type.IsAbstract
                         && !type.IsInterface)
          .As<IStorageMechanism>()
          .SingleInstance();

        //  register IStorageHandler implementors
        builder.RegisterAssemblyTypes(caliburnAssembly)
          .Where(type => typeof(IStorageHandler).IsAssignableFrom(type)
                         && !type.IsAbstract
                         && !type.IsInterface)
          .As<IStorageHandler>()
          .SingleInstance();

        // The constructor of these services must be called
        // to attach to the framework properly.
        var phoneService = new PhoneApplicationServiceAdapter(RootFrame);
        var navigationService = new FrameAdapter(RootFrame, false);

        builder.Register<IPhoneContainer>(c => new AutofacPhoneContainer(c)).SingleInstance();
        builder.RegisterInstance<INavigationService>(navigationService).SingleInstance();
        builder.RegisterInstance<IPhoneService>(phoneService).SingleInstance();
        builder.Register<IEventAggregator>(c => new EventAggregator()).SingleInstance();
        builder.Register<IWindowManager>(c => new WindowManager()).SingleInstance();
        builder.Register<IVibrateController>(c => new SystemVibrateController()).SingleInstance();
        builder.Register<ISoundEffectPlayer>(c => new XnaSoundEffectPlayer()).SingleInstance();
        builder.RegisterType<StorageCoordinator>().AsSelf().SingleInstance();
        builder.RegisterType<TaskController>().AsSelf().SingleInstance();

        //  allow derived classes to add to the container
        ConfigureContainer(builder);

        //  build the container
        container = builder.Build();

        //  start services
        container.Resolve<StorageCoordinator>().Start();
        container.Resolve<TaskController>().Start();

        //  add custom conventions for the phone
        AddCustomConventions();
    }

    protected override object GetInstance(Type service, string key)
    {
        object instance;
        if (string.IsNullOrEmpty(key))
        {
            if (container.TryResolve(service, out instance))
                return instance;
        }
        else
        {
            if (container.TryResolveNamed(key, service, out instance))
                return instance;
        }
        throw new Exception(string.Format("Could not locate any instances of contract {0}.", key ?? service.Name));
    }

    protected override IEnumerable<object> GetAllInstances(Type service)
    {
        return container.Resolve(typeof(IEnumerable<>).MakeGenericType(service)) as IEnumerable<object>;
    }

    protected override void BuildUp(object instance)
    {
        container.InjectProperties(instance);
    }

    private static void AddCustomConventions()
    {
        ConventionManager.AddElementConvention<Pivot>(Pivot.ItemsSourceProperty, "SelectedItem", "SelectionChanged").ApplyBinding =
            (viewModelType, path, property, element, convention) =>
            {
                if (ConventionManager
                    .GetElementConvention(typeof(ItemsControl))
                    .ApplyBinding(viewModelType, path, property, element, convention))
                {
                    ConventionManager
                        .ConfigureSelectedItem(element, Pivot.SelectedItemProperty, viewModelType, path);
                    ConventionManager
                        .ApplyHeaderTemplate(element, Pivot.HeaderTemplateProperty, viewModelType);
                    return true;
                }

                return false;
            };

        ConventionManager.AddElementConvention<Panorama>(Panorama.ItemsSourceProperty, "SelectedItem", "SelectionChanged").ApplyBinding =
            (viewModelType, path, property, element, convention) =>
            {
                if (ConventionManager
                    .GetElementConvention(typeof(ItemsControl))
                    .ApplyBinding(viewModelType, path, property, element, convention))
                {
                    ConventionManager
                        .ConfigureSelectedItem(element, Panorama.SelectedItemProperty, viewModelType, path);
                    ConventionManager
                        .ApplyHeaderTemplate(element, Panorama.HeaderTemplateProperty, viewModelType);
                    return true;
                }

                return false;
            };
    }

    #endregion
}

EDIT I have created a fork of Caliburn.Micro.Autofac and fixed the issue on GitHub. Hopefully the pull request will be accepted and this will become part of the main repository.

For now, you can access the bootstrapper, and AutofacPhoneContainer from here - https://github.com/distantcam/Caliburn.Micro.Autofac/tree/master/src/Caliburn.Micro.Autofac-WP7

Upvotes: 2

Related Questions