2011-09-29 96 views
2

我有一个简单的容器层次结构,它具有在Shell MEFBootstrapper中使用Directory目录定义的父容器,以及使用不同目录创建父容器的子容器。MEF子容器模块未初始化

我的子容器也使用DirectoryCatalog(与父级不同的路径),我可以看到容器在运行时有装配和零件信息。

但是,位于子容器中的模块的Initialize()方法永远不会被调用。

我的目标是使用子容器作为会话结构,允许用户创建新会话并在它们之间切换。但是,如果我不能让组成模块初始化(并将他们的观点放入区域),我就会陷入困境。

我曾经想过使用事件聚合器从会话管理器中引发一个事件,以允许模块监听事件并自行初始化,但这似乎也不起作用。

i。为什么不初始化调用加载到子容器中的模块 ii。我怎样才能“触发”从容器实例初始化(在模块上下文之外?)你可以迭代容器中的程序集并触发初始化吗?

[从MefBootstrapper在壳牌项目]

protected override DependencyObject CreateShell() 
    { 
     ExportProvider ep = this.Container as ExportProvider; 
     this.Container.ComposeExportedValue(ep); 

[从管理我的会话(容器)的服务]

[ImportingConstructor] 
    public SessionService(ExportProvider provider) 
    { 

[构造新的会话(容器)]

private void Init(ComposablePartCatalog catalog, ExportProvider provider, string name, int callId, bool useContextProxy) 
    { 
     this._Name = name; 
     this._CallID = callId; 
     this.startTime = DateTime.Now; 
     this.appHost = new CompositionContainer(catalog, new ExportProvider[] { provider }); 
    } 

=====

被要求包括我的模块代码的initialize方法没有被调用(尽管被加载到问题的容器中......我甚至可以懒惰实例化模块,但直接调用Initialize()会导致注入操作在方法中失败正确。

namespace Module1 
{ 
//, InitializationMode = InitializationMode.OnDemand 
[ModuleExport("Module1.ModuleInit", typeof(Module1.ModuleInit))] 
public class ModuleInit : IModule 
{ 
    private readonly IRegionManager _regionManager; 
    public IServiceLocator _serviceLocator; 

    [ImportingConstructor] 
    public ModuleInit(IRegionManager regionManager, IServiceLocator serviceLocator) 
    { 
     _regionManager = regionManager; 
     _serviceLocator = serviceLocator; 
    } 

    #region IModule Members 


    public void Initialize() 
    { 
     // Use View Discovery to automatically display the MasterView when the TopLeft region is displayed. 
     _regionManager.RegisterViewWithRegion(RegionNames.TopLeftRegion,() => _serviceLocator.GetInstance<MasterView>()); 
    } 

    #endregion 
} 

}

+0

你可以用'Initialize'方法显示一个示例模块吗? –

+0

当然,非常简单,直接从VS2010中的PRISM模板项目:(请参阅编辑) –

回答

1

我已经有这个问题很多次,解决它是非常简单的。

从模块中删除构造函数。 Prism模块的激活方式与传统导出类型不同,因此模块不能使用ImportingConstructor导入所需的服务。而是使用Initialize方法中的ServiceLocator初始化它们。

这将工作:

[ModuleExport("Module1.ModuleInit", typeof(Module1.ModuleInit))] 
public class ModuleInit : IModule 
{ 
    private readonly IRegionManager _regionManager; 

    public void Initialize() 
    { 
     _regionManager = ServiceLocator.Current.GetInstance<IRegionManager>(); 

     _regionManager.RegisterViewWithRegion(RegionNames.TopLeftRegion,() => _serviceLocator.GetInstance<MasterView>()); 
    } 
} 

我也认为这种行为是一种令人不安。

+0

感谢您的建议,但即使对这些更改,Initialize方法也不会被调用。当在MEFBootstrapper之外创建(子)容器时,没有调用ConfigureContainer方法,那么该容器的目录中的模块如何获得初始化?我知道我错过了一些非常明显的东西。 –

+0

“创建”是什么意思?它是在一个容器内组成还是仅仅是实例化的? – Ucodia

+0

我写的是关于子容器创建的。它们使用以下内容创建: this.appHost = new CompositionContainer(catalog,new ExportProvider [] {provider}); –

3

我下载了你的代码并看了一下。我立即发现了这个问题。引导程序实际上是让得益于出口到DirectoryCatalog这样的:

DirectoryCatalog catalog = new DirectoryCatalog("."); 
this.AggregateCatalog.Catalogs.Add(catalog); 

这意味着你会得到从这个目录中的组件出口。所以你只需要将所有的程序集与导出的类型复制到目录“。”中,也就是执行目录(Debug/bin)中。

只需复制模块1 1和Module2的bin目录和寄托都将正常组成:)

其实我发现,应该在模块的bin目录复制生成后事件无法工作。也许是因为你改名了。所以,如果你想它会自动复制建成后的组件只需更换该一个实际的生成后事件:

copy "$(TargetDir)\$(TargetFileName)" "$(TargetDir)\..\..\..\Shell\bin\$(ConfigurationName)\" 
+0

再一次,感谢您花时间看这个。 但是,如果我将Module1和Module2放入根目录中,它们将被加载到初始目录中,然后可以从根CompositionContainer中获得。我的目标(可能是不恰当的),是将Module1和Module2分隔成一个小孩CompositionContainer * only *,以便CompositionContainer根可以*不*满足这些模块的Import请求...只有子容器可以。但是我开始认为这只是一个糟糕的主意,而且我应该将所有模块加载到单个目录/容器中。 –

+0

是的,它最有可能将您在一个地方输入的所有内容导出。如果您需要的是在需要时初始化模块,则可以通过将模块配置为OnDemand来延迟加载。 – Ucodia

0

我在我的模块初始化这个同样的问题()没有被调用的方法......我我意识到我的Initialize方法中的“override”关键字没有在模块基类中声明为虚拟的,我的所有模块都继承自该方法...添加了“覆盖”并且它工作正常!