2011-09-29 97 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」關鍵字沒有在模塊基類中聲明爲虛擬的,我的所有模塊都繼承自該方法...添加了「覆蓋」並且它工作正常!