Skip to content

Instantly share code, notes, and snippets.

@bryanhunter
Created August 5, 2011 16:29
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bryanhunter/1127914 to your computer and use it in GitHub Desktop.
Save bryanhunter/1127914 to your computer and use it in GitHub Desktop.
Castle bootstrapper for Caliburn.Micro
// Hooks up Castle Windsor as the container for your Caliburn.Micro application.
// Turns on support for delegate factory methods (e.g. passing the factory "Func<XyzEditViewModel>" as a constructor arg)
// Dependencies: In addition to Caliburn.Micro you will need to reference Castle.Core and Castle.Windsor
public class CastleBootstrapper<TRootViewModel> : Bootstrapper<TRootViewModel>
{
private ApplicationContainer _container;
protected override void Configure()
{
_container = new ApplicationContainer();
_container.AddFacility<TypedFactoryFacility>();
}
protected override object GetInstance(Type service, string key)
{
return string.IsNullOrWhiteSpace(key)
? _container.Resolve(service)
: _container.Resolve(key, service);
}
protected override IEnumerable<object> GetAllInstances(Type service)
{
return (IEnumerable<object>)_container.ResolveAll(service);
}
protected override void BuildUp(object instance)
{
instance.GetType().GetProperties()
.Where(property => property.CanWrite && property.PropertyType.IsPublic)
.Where(property => _container.Kernel.HasComponent(property.PropertyType))
.ForEach(property => property.SetValue(instance, _container.Resolve(property.PropertyType), null));
}
}
public class ApplicationContainer : WindsorContainer
{
public ApplicationContainer()
{
Register(
Component.For<IWindowManager>().ImplementedBy<WindowManager>().LifeStyle.Is(LifestyleType.Singleton),
Component.For<IEventAggregator>().ImplementedBy<EventAggregator>().LifeStyle.Is(LifestyleType.Singleton)
);
RegisterViewModels();
}
private void RegisterViewModels()
{
Register(AllTypes.FromAssembly(GetType().Assembly)
.Where(x => x.Name.EndsWith("ViewModel"))
.Configure(x => x.LifeStyle.Is(LifestyleType.Transient)));
}
}
// If you don't already have a ForEach extension method in your project here you go:
public static class ForEachExtension
{
public static void ForEach<T>(this IEnumerable<T> source, Action<T> action)
{
foreach (T element in source)
{
action(element);
}
}
}
@HEskandari
Copy link

You don't need to re-implement the whole thing, just use Bootstrapper and override CreateContainer method there and create an instance of WindsorAdapter. The adapter will register necessary components for Caliburn framework so you won't have to register them like you do above (e.g. WindowManager, EventAggregator, etc.)

@bryanhunter
Copy link
Author

Hadi, I believe you are confusing Caliburn (http://caliburn.codeplex.com) with Caliburn.Micro (http://caliburnmicro.codeplex.com/). This gist shows how to hook up Castle Windsor as the container for your Caliburn.Micro apps. Caliburn.Micro does not provide an adapter for Windsor and CM's Bootstrapper does not have a CreateContainer method to override. This gist provides the core functionality of Caliburn 2.0's "Caliburn.Windsor.dll" for users of the lighter Caliburn.Micro framework.

Thanks for the comment though.

@markawil
Copy link

New to using Caliburn, so forgive me for this question, where in this bootstrapper do I wire up my dependencies for Windsor, lets say I have multiple implementations of the same interface and depending on certain criteria, say in the app.config I choose certain concrete implementations. I do this in my other projects and I'm trying to figure out where this goes using Calibrun.Micro and your bootstrapper.

@bryanhunter
Copy link
Author

Good question mark.

In Castle, the first registration wins (it becomes the default registration). If you want app.config registrations to win, you could modify ApplicationContainer::ctor() to look like this

public ApplicationContainer()
            : base(new XmlInterpreter(new ConfigResource("castle")))
{
    .... everything else stays the same
}

Here's a Castle sample you might find helpful:
https://github.com/NashDotNet/lab-dependency-injection/blob/master/src/Castle/CastleWithXmlAndCodeRegistration/Program.cs

If you want to add in-code registrations, you could put them in ApplicationContainer:ctor() alongside the IWindowManager and IEventAggregator registration (or at any point after that).

Hope this helps!
-Bryan

@HEskandari
Copy link

HEskandari commented Nov 18, 2011 via email

@HEskandari
Copy link

HEskandari commented Jan 18, 2012 via email

@markawil
Copy link

Thanks for the reply.

Yeah I deleted my question after finding the answer in the documentation about SelectAssembly.

Now, you mentioned the container. So if I have say a MenuBuilder that builds up a menu, with menu items, and I set the Action of one of the MenuItem clicks to open up a new window, I resolve that by injecting into this MenuBuilder the ViewModel of this window I want to open? If I get the viewmodel how do I then open up it's corresponding view?

-mark

@HEskandari
Copy link

HEskandari commented Jan 18, 2012 via email

@markawil
Copy link

I'm using Castle Windsor.

In the past using basic MVVM I would give the ViewModel a Show() method on it's interface, that Show() method would then call the Show() of the View, and the IView was injected into the constructor of the ViewModel.

@HEskandari
Copy link

HEskandari commented Jan 18, 2012 via email

@markawil
Copy link

Looked through Payroll solution 1 and 2, couldn't compile probably because of lacking DevEx products.

But I noticed you're using what looks like Caliburn and not Caliburn.Micro as your bootstrapping was done in the App.xaml.cs.

I couldn't find where you fire up a new view or UI in the code in the Payroll part 2 solution. That's really all I need to get to, presenting a new window or view.

@HEskandari
Copy link

HEskandari commented Jan 19, 2012 via email

@HEskandari
Copy link

HEskandari commented Jan 21, 2012 via email

@jasonching
Copy link

Thanks Brian. This is what I was looking for.

Any idea about how the ViewModel release management should be handled?

When I have to show a new window, I am first using Castle's container to resolve the new ViewModel, and then invoking the ShowWindow method of WindowManager to take care of the rest.

But how I can make sure this is released from the container after the window is closed?

Accounting to the document, even though the LifeStyle of view model is set to transient, it's still necessary to invoke Release when the window is closed.
http://docs.castleproject.org/Default.aspx?Page=LifeStyles&NS=Windsor&AspxAutoDetectCookieSupport=1#Transient_5

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment