Search code examples
c#wpftabcontrolcaliburn.micro

Caliburn.Mirco Simple Container Multiple Interface Instances


I'm essentially trying to run a tab control using Caliburn Micro's Simple Container where each Tab View Model implements an interface "IMainScreenTabItem" in c#.

When setting up the container I can do something like this:

container.AllTypesOf<IMainScreenTabItem>(Assembly.GetExecutingAssembly());

This will allow me to get all view models that implement IMainScreenTabItem in the constructor for the tab control view model like this:

public TabControlViewModel(IEnumerable<IMainScreenTabItem> tabs){ Items.AddRange(tabs); }

The problem with this specific application is that I don't want the implementations to be kept alive as singletons when the the TabControlViewModel is disposed and the .AllTypesOf Method registers them as singletons.

I can create them all by hard coding each view model like so:

container.Instance(container)
            .PerRequest<IMainScreenTabItem, TabItem1>()
            .PerRequest<IMainScreenTabItem, TabItem2>();

and so on..but that feels a little messy.

I was thinking something like this:

var tabs = GetType().Assembly.GetTypes()
            .Where(type => type.IsClass)
            .Where(type => !type.IsAbstract)
            .Where(type => type.GetInterface(nameof(IMainScreenTabItem)) != null);

tabs.ToList().ForEach(tab => container.RegisterPerRequest(typeof(IMainScreenTabItem), tab.ToString(), tab));

The problem with that is .RegisterPerRequest doesn't allow me to have multiple implementations of a single interface like .PerRequest does.

Caliburn Micro's website describes the difference as such "Per Request registration causes the creation of the returned entity once per request. This means that two different requests for the same entity will result in two distinct instances being created." https://caliburnmicro.com/documentation/simple-container

So I would like to do something like this:

tabs.ToList().ForEach(tab => container.PerRequest<IMainScreenTabItem, tab>());

but obviously I get the 'tab is a variable but is used like a type' Error message.

Any ideas on this would be greatly appreciated! This is my first Caliburn Micro project so I might just be missing something simple.

Thanks in advance!


Solution

  • Can't you use a factory method that resolves all implementations of IMainScreenTabItem from the assembly?:

    container.Handler<TabControlViewModel>(container =>
    {
        var tabs = AppDomain.CurrentDomain.GetAssemblies()
            .SelectMany(s => s.GetTypes())
            .Where(t => t.GetInterfaces().Contains(typeof(IMainScreenTabItem)))
            .Select(t => (IMainScreenTabItem)Activator.CreateInstance(t))
            .ToArray();
        return new TabControlViewModel();
    });