首页 > 解决方案 > 在 MVVM 中使用 MEF 创建 ViewModel

问题描述

这会有点长,所以请抓紧时间。

我有一个Caliburn.Micro用于实现 MVVM 模式的项目。对于 IoC,我使用的是 MEF。所有的 ViewModel 都标有属性[Export(typeof(IScreen))]IScreen中定义Caliburn.Micro

在我的BootStrapper文件中,我像这样设置了 MEF:

private CompositionContainer container;

protected override void Configure()
{

    //Set up MEF

    container = new CompositionContainer(new AggregateCatalog``AssemblySource.Instance.Select``(x => new AssemblyCatalog(x)).OfType<ComposablePartCatalog>()));

    var batch = new CompositionBatch();

    batch.AddExportedValue<IWindowManager>(new WindowManager());

    batch.AddExportedValue<IEventAggregator>(new EventAggregator());

    batch.AddExportedValue(container);

    container.Compose(batch);

    //Other stuff
}

现在,我展示了第一个 ViewModel 使用

protected override void OnStartup(object sender, StartupEventArgs e) => DisplayRootViewFor<ViewModels.Main.MainViewModel>();

这一切都很好,花花公子。现在,当我想从一个切换ViewModel到另一个时,问题就开始了。

ViewModel 的一个示例是:

[PartCreationPolicy(CreationPolicy.NonShared), Export(typeof(IScreen))]
sealed class SampleViewModel: ScreenVMwithUoW<IAddItemUoW>
{
    [ImportingConstructor]
    public SampleViewModel(IAddItemUoW uow, IEventAggregator eventAggregator) : base(uow, eventAggregator)
    {

    }
    //bla bla bla
}

假设我想打开SampleViewModel和关闭我的MainViewModel. 我如何使用 MEF 做到这一点?

这是我现在正在做的事情:

[Export(typeof(IScreenFactory))]
class ScreenFactory : IScreenFactory
{
    private Dictionary<Type, ExportFactory<IScreen>> _screenDictionary { get;  set; }        
    private IEnumerable<ExportFactory<IScreen>> _screenfactoryCollection { get; set; }
    private ExportLifetimeContext<IScreen> _currentScreenLifeTimeCtx { get; set; }        

    [ImportingConstructor]
    public ScreenFactory([ImportMany(AllowRecomposition = true)] IEnumerable<ExportFactory<IScreen>> screenList)
    {
        _screenfactoryCollection = screenList;
        _reportfactoryCollection = reportsList;            
    }

    public IScreen GetScreen(Type t)
    {
        if (_screenDictionary == null)
        {
            PopulateScreenDictionary(_screenfactoryCollection);
        }

        _currentScreenLifeTimeCtx = _screenDictionary[t].CreateExport();                
        return _currentScreenLifeTimeCtx.Value;
    }

    private void PopulateScreenDictionary(IEnumerable<ExportFactory<IScreen>> screenfactories)
    {
        _screenDictionary = screenfactories.ToDictionary(c => c.CreateExport().Value.GetType(), c => c);
    }

    public void DisposeCurrentScreenContext()
    {
        _currentScreenLifeTimeCtx?.Dispose();
    }

    public void Dispose()
    {
        DisposeCurrentScreenContext();
    }
}

每当我需要 a 的新实例时ViewModel,我都会这样做:

DeactivateItem(ActiveItem, true);
_vmFactory.DisposeCurrentScreenContext();
ActivateItem(_vmFactory.GetScreen(NextViewModelName));

这不能是这样做的正常方式。此外,这也增加了对性能的巨大冲击,尤其是应用程序的启动时间,当ViewModels 的数量增加到大约 25-30 时。

如果可能的话,我还想避免使用服务定位器模式。我也愿意使用适当的 IoC Container 而不是MEF,但MEF允许我轻松添加 ViewModels。只需添加注释即可[Export(typeof(IScreen))]完成工作。

标签: c#mvvminversion-of-controlmefioc-container

解决方案


推荐阅读