Caliburn Micro中的实例

时间:2014-02-03 04:04:33

标签: mef caliburn.micro caliburn caliburn.micro.reactiveui

我们第一次使用Caliburn Micro。 我们有一个继承自ShellViewModel的AppBootstrapper。 情况是VieModels应该具有相同的实例,除非它被重置。

我们每次都可以实现共享或不共享,但是在需要时释放导出仍然是一个谜。

  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();
    }
}

现在AViewModel和BViewModel都有单个实例。 只要单击“释放”按钮,我就想拥有AViewModel和BViewModel的新实例。

希望尽快得到回复。

此致 的Vivek

1 个答案:

答案 0 :(得分:2)

使用IoC容器时,代码中唯一应将其作为依赖项的部分应该是composition root(即本例中的AppBootstrapper)。您不应该在代码中的任何其他位置注入或引用容器(可能除了工厂之外)。

如果您希望ShellViewModel控制子视图模型的生命周期(AB),那么您应该考虑将视图模型工厂注入ShellViewModel (通过构造函数注入,如果它们是必需的依赖项)。

您的AViewModelFactory只有一个Create方法,可以返回AViewModel的新实例,同样使用BViewModelFactory。您可以直接在工厂中新建视图模型。如果您的视图模型本身具有较大的依赖关系链,那么您可以考虑在工厂中添加对容器的引用,但最好考虑查看MEF ExportFactory<T>类型。