Caliburn Micro:基于MEF的场景的插件相关问题

时间:2011-06-03 17:35:29

标签: mef caliburn.micro

我有一个WPF应用程序托管一些视图(用户控件)及其视图模型的场景,在其插件文件夹中找到MEF导出的部件。应用程序将其数据与配置文件一起加载,配置文件还说明应在可用的部分之间导入哪些部分。

第一个问题与MEF引导程序有关:我如何自定义它以让它知道插件文件夹?我知道它的 SelectAssemblies 覆盖,但它需要程序集,而我的典型方法是MEF目录目录。我不想为目录中找到的每个DLL使用 Assembly.LoadFrom 之类的方法:MEF就是为了这个目的(生命周期管理等)。那么如何在引导程序中执行与 DirectoryCatalog 构建的MEF AggregateCatalog 类似的操作呢?

第二个问题:一旦我有了我需要的VM列表,我想实例化它们。其中一些需要注入CM服务,如 IEventAggregator IWindowManager ,因此他们有相应的导入构造函数,因此我需要CM为我实例化它们:但我需要以编程方式执行此操作,因此我不能仅在属性或导入构造函数上使用Import属性。

对于视图也是如此:一旦我获得了VM,我需要CM来创建它们并将相应的VM设置为它们的数据上下文;但我不能使用窗口管理器,因为我只想获取它们,然后以编程方式将它们(它们是用户控件)添加到选项卡控件,该控件根据数据配置的不同组成。

我正在使用MEF,因为该应用程序是以插件为中心的,因此在用作IoC时我可以坚持其局限性。但我想利用CM实例化我的视图和视图模型(所有包含在几个插件DLL中)并正确绑定它们。任何人都可以提供一些提示或指向有关此的样本或文档吗?

第二次更新,正如所承诺的那样:):

我基本上遵循以下步骤:

  1. 根据某些应用程序逻辑实例化(使用MEF)所需的VM。所有VM都是MEF导出,托管在插件文件夹中的几个插件中。

  2. 对于每个VM,请致电:

  3. static private object LocateViewFor(object viewmodel)
    {
      UIElement view = ViewLocator.LocateForModel(viewmodel, null, null);
        ViewModelBinder.Bind(viewmodel, view, null);
      return view;
    }
    

    这应该通过CM来反映我的观点,这也将满足他们的导入并将每个视图绑定到其VM。使用针对WPF修改的“标准”MefBootstrapper(参见例如here)。无论如何,这不起作用并返回null。

    我必须告诉引导程序它可以在哪里找到我的MEF导出。它们位于plugins文件夹中,如果我没有使用CM,我会使用MEF DirectoryCatalog检查其内容。 CM中bootstrappers的典型扩展点是SelectAssemblies重写,它要求我返回Assembly对象列表。从文件夹加载所有程序集不是一种选择。根据上面引用页面中的建议,我可以在我的引导程序中添加类似这样的方法:

    private IEnumerable GetDirectoryCatalogs()
    {
     return new ComposablePartCatalog[]
     {
     new DirectoryCatalog(AppDomain.CurrentDomain.BaseDirectory)
     // TODO other plugins folders...
      };
    }
    

    并修改其配置代码,如:

    _container = new CompositionContainer(
      new AggregateCatalog(AssemblySource.Instance.Select(x => new AssemblyCatalog(x)).OfType()
      .Union(GetDirectoryCatalogs())));
    

    这实际上似乎加载了MEF所需的程序集,但是将它们“注册”到CM AssemblySource是不够的。实际上:我可以通过MEF检索VM,但当我要求CM获取相应的时候view(使用上面的方法,或者调用IWindowManager.ShowDialog(myviewmodel,null))我从方法中得到null,或者(对于第二个示例)“占位符”文本框说我的VM的视图不能位于。

    这似乎与视图(如viewmodel)托管到不同的程序集(我的MEF插件)这一事实有关。我确保view和viewmodel 共享相同的命名空间,并且遵循SomeNamespace.SampleViewModel类型的命名约定 - SomeNamespace.SampleView;此外,视图和视图模型都是通过使用[Export] 进行装饰来导出的,并从通用接口派生。尽管如此,在处理外部程序集时,我无法让CM按预期工作。 MEF工作正常,包括所有的进口和出口,但是一旦CM进入等式,它就无法做到“神奇”并从VM找到一个视图。

    任何提示?

1 个答案:

答案 0 :(得分:1)

我以前从未对Caliburn Micro做过任何事情,但它是否使用CompositionInitializer组件来满足进口需求?如果是这样,您可以使用CompositionHost手动初始化用于满足导入的容器,例如:

var catalog = new AggregateCatalog(
    new DirectoryCatalog("bin"),
    new DirectoryCatalog("Plugins"));

CompositionHost.Initialise(catalog);

CompositionInitialiser.SatisfyImports(...)的任何调用都将使用根据您创建的目录构建的容器。

如果您希望能够以编程方式创建导出实例,则需要引用实际的CompositionContainer本身。但要做到这一点,我们需要另一种初始化构图的替代方法。您可以创建一个容器并保留对它的引用,例如:

var catalog = new AggregateCatalog(
    new DirectoryCatalog("bin"),
    new DirectoryCatalog("Plugins"));
var container = new CompositionContainer(catalog);
CompositionHost.Initialise(container);

Container = container;

...其中Container是对CompositionContainer实例的静态引用。我们已将调用更改为CompositionHost以确定CompositionInitializer将使用的确切容器,以便所有仍然正常工作,但我们有一个容器可用于创建特定实例,例如:

var viewModel = Container.GetExport<ISomeViewModel>();

这有帮助吗?