Instance in Caliburn Micro

We are using Caliburn Micro for the first time. We have a AppBootstrapper inherited from ShellViewModel. Situvation is that VieModels should have the same instance unless it is reset.

we are able to achieve shared or not shared everytime, but releasing the export whenever needed is still a mystery.

  public class AppBootstrapper : Bootstrapper<ShellViewModel>
{
    private static CompositionContainer _container;

    protected override void Configure()
    {
        try
        {
            _container = new CompositionContainer(
                new AggregateCatalog(AssemblySource.Instance.Select(x => new AssemblyCatalog(x))));

            var batch = new CompositionBatch();

            batch.AddExportedValue<IWindowManager>(new WindowManager());
            batch.AddExportedValue<IEventAggregator>(new EventAggregator());
            batch.AddExportedValue(_container);

            StyleManager.ApplicationTheme = ThemeManager.FromName("Summer");

            _container.Compose(batch);
        }
        catch (Exception exception)
        {
        }
    }

    public static void ReleaseAll()
    {

    }

    protected override object GetInstance(Type serviceType, string key)
    {
        try
        {
            var contract = string.IsNullOrEmpty(key) ? AttributedModelServices.GetContractName(serviceType) : key;
            var exports = _container.GetExportedValues<object>(contract);
            if (exports.Any())
                return exports.First();
            throw new Exception(string.Format("Could not locate any instances of contract {0}.", contract));
        }
        catch (ReflectionTypeLoadException ex)
        {
            foreach (Exception inner in ex.LoaderExceptions)
            {
                // write details of "inner", in particular inner.Message
            }
            return null;
        }
    }

    protected override IEnumerable<object> GetAllInstances(Type serviceType)
    {
        try
        {
            return _container.GetExportedValues<object>(AttributedModelServices.GetContractName(serviceType));
        }
        catch (Exception exception)
        {
            return null;
        }
    }

    protected override void BuildUp(object instance)
    {
        _container.SatisfyImportsOnce(instance);
    }
}

ShellViewModel

  [Export(typeof(ShellViewModel))]
public sealed class ShellViewModel : Conductor<IScreen>.Collection.OneActive, IHandle<object>
{
    [ImportingConstructor]
    public ShellViewModel(CompositionContainer compositionContainer, IEventAggregator eventAggregator)
    {
        CompositionContainer = compositionContainer;
        EventAggregator = eventAggregator;
        eventAggregator.Subscribe(this);

        Items.Add(compositionContainer.GetExportedValue<AViewModel>());
        Items.Add(compositionContainer.GetExportedValue<BViewModel>());

        ActivateItem(Items.Single(p => p.DisplayName == AppMessageType.A.ToString()));
    }

    public IEventAggregator EventAggregator { get; set; }
    public CompositionContainer CompositionContainer { get; set; }

    public void Handle(object message)
    {
        //throw new System.NotImplementedException();
    }

    public void B()
    {
        ActivateItem(Items.Single(p => p.DisplayName == AppMessageType.B.ToString()));
    }

    public void A()
    {
        ActivateItem(Items.Single(p => p.DisplayName == AppMessageType.A.ToString()));
    }

    public void RESET()
    {
        AppBootstrapper.ReleaseAll();
        ActivateItem(Items.Single(p => p.DisplayName == AppMessageType.A.ToString()));
    }

    public enum AppMessageType
    {
        A,
        B
    }
}

AViewModel

[Export(typeof(AViewModel))]
public sealed class AViewModel : Conductor<IScreen>.Collection.OneActive, IHandle<object>
{
    [ImportingConstructor]
    public AViewModel(CompositionContainer compositionContainer, IEventAggregator eventAggregator)
    {
        DisplayName = ShellViewModel.AppMessageType.A.ToString();

        CompositionContainer = compositionContainer;
        EventAggregator = eventAggregator;
        eventAggregator.Subscribe(this);
    }

    public IEventAggregator EventAggregator { get; set; }
    public CompositionContainer CompositionContainer { get; set; }


    public void Handle(object message)
    {
        //throw new System.NotImplementedException();
    }
}

BViewModel

 [Export(typeof(BViewModel))]
public sealed class BViewModel : Conductor<IScreen>.Collection.OneActive, IHandle<object>
{
    [ImportingConstructor]
    public BViewModel(CompositionContainer compositionContainer, IEventAggregator eventAggregator)
    {
        DisplayName = ShellViewModel.AppMessageType.B.ToString();

        CompositionContainer = compositionContainer;
        EventAggregator = eventAggregator;
        eventAggregator.Subscribe(this);
    }

    public IEventAggregator EventAggregator { get; set; }
    public CompositionContainer CompositionContainer { get; set; }


    public void Handle(object message)
    {
        //throw new System.NotImplementedException();
    }
}

Now AViewModel and BViewModel have single instance. Whenever Release Button is clicked i want to have new instance of AViewModel and BViewModel.

Hoping to get a reply soon.

Regards, Vivek

Answers


When working with an IoC container, the only part of your code that should take it as a dependency should be your composition root (i.e. your AppBootstrapper in this case). You shouldn't be injecting or referencing the container anywhere else in your code (except possibly factories).

If you want your ShellViewModel to control the lifetime of your child view models (A and B), then you should consider injecting view model factories into your ShellViewModel (via constructor injection if they are required dependencies).

Your AViewModelFactory would just have a single Create method that returns a new instance of AViewModel, likewise with the BViewModelFactory. You can simply new up your view models directly in the factories. If your view models have large dependency chains themselves, then you could consider adding a reference to your container in the factories, although preferably consider looking into the MEF ExportFactory<T> type.


Need Your Help

<body> height extends on internet explorer 8 and below

html css internet-explorer

The &lt;body&gt; height of my homepage extends to about 200% on earlier IE. The website is http://www.graetz-ran.co.il/.

JAX-RS custom SecurityContext leads to wrong error code in Jersey

java http rest jersey http-status-code-403

I followed the Jersey tutorials to implement a completely custom SecurityContext for my application. I created a custom ContainerRequestFilter to set the SecurityContext as follows: