MEF程序設計指南七:使用目錄(Catalog)動態裝載xap與目錄篩選(Filtered Catalog)

  如果不使用MEF進行託管擴展處理,只有通過WebClient進行程序包的下載、解析。實際上MEF的動態下載的底層實現一樣是使用的WebClient,然後利用AggregateCatalog進行動態組合,詳細可查看MEF的源代碼(路徑:Composition.Initialization/System/ComponentModel/Composition/Hosting/DeploymentCatalog.cs)。

 

  在上一篇程序設計指南《MEF程序設計指南六:MEF中的目錄服務(DeploymentCatalog)》中介紹了MEF的目錄服務,並對MEF的目錄服務進行了接口封裝,其中有一個接口就是專門封裝的使用MEF的目錄進行.xap程序包的動態裝載的。

public void AddXap(string relativeUri, Action<AsyncCompletedEventArgs> completedAction)
{
    DeploymentCatalog catalog;
    
if (!_catalogs.TryGetValue(relativeUri, out catalog))
    {
        catalog 
= new DeploymentCatalog(relativeUri);

        
if (completedAction != null)
            catalog.DownloadCompleted 
+= (s, e) => completedAction(e);
        
else
            catalog.DownloadCompleted 
+= DownloadCompleted;

        catalog.DownloadAsync();
        _catalogs[relativeUri] 
= catalog;
        _aggregateCatalog.Catalogs.Add(catalog);

    }
}

 

  其應用也非常簡單,通過MEF的導入將接口導入到需要使用的地方,然後直接調用上面的方法即可實現對指定路徑的xap包的動態下載以及組合。

[Import]
public IDeploymentService Service { getset; }

private void button1_Click(object sender, System.Windows.RoutedEventArgs e)
{
    
this.Service.AddXap("MEFTraining.MefCatalogs.Parts.xap"null);
}

 

  到這裏我們還需要學習另外一個接口的使用,IPartImportsSatisfiedNotification接口就是一個當有新的部件進行裝配成功後的一個通知接口,可以準確的監聽到MEF容器的組合,一旦有新的插件部件進行導入裝載到MEF容器中,此接口就會自動的得到通知。其內部就一個接口方法,詳細如下代碼塊:

public void OnImportsSatisfied()
{
            
}

 

  在使用MEF目錄進行導出部件託管的時候,在某些需求下或許只需要其中的一個部件,這種情況可以通過遍歷部件集合得到。然而MEF也爲此提供了一種解決方案,那就是使用目錄過濾篩選功能。MEF中的ComposablePartCatalog類和INotifyComposablePartCatalogChanged接口就是專門用來實現目錄篩選的,可以如下代碼段中演示的對目錄過濾的封裝。

public class FilteredCatalog : ComposablePartCatalog, INotifyComposablePartCatalogChanged
{
    
private readonly ComposablePartCatalog _inner;
    
private readonly INotifyComposablePartCatalogChanged _innerNotifyChange;
    
private readonly IQueryable<ComposablePartDefinition> _partsQuery;

    
public FilteredCatalog(ComposablePartCatalog inner,
                        Expression
<Func<ComposablePartDefinition, bool>> expression)
    {
        _inner 
= inner;
        _innerNotifyChange 
= inner as INotifyComposablePartCatalogChanged;
        _partsQuery 
= inner.Parts.Where(expression);
    }

    
public event EventHandler<ComposablePartCatalogChangeEventArgs> Changed
    {
        add
        {
            
if (_innerNotifyChange != null)
                _innerNotifyChange.Changed 
+= value;
        }
        remove
        {
            
if (_innerNotifyChange != null)
                _innerNotifyChange.Changed 
-= value;
        }

    }

    
public event EventHandler<ComposablePartCatalogChangeEventArgs> Changing
    {
        add
        {
            
if (_innerNotifyChange != null)
                _innerNotifyChange.Changing 
+= value;
        }
        remove
        {
            
if (_innerNotifyChange != null)
                _innerNotifyChange.Changing 
-= value;
        }

    }

    
public override System.Linq.IQueryable<ComposablePartDefinition> Parts
    {
        
get
        {
            
return _partsQuery;
        }
    }
}

 

   通過上面的封裝,使用目錄過濾功能之需要傳入正確的篩選表達式就可以了,按照MEF中的約定其篩選表達式應如下格式。

var filteredCat = new FilteredCatalog(catalog,
    def 
=> def.Metadata.ContainsKey(CompositionConstants.PartCreationPolicyMetadataName) &&
        ((CreationPolicy)def.Metadata[CompositionConstants.PartCreationPolicyMetadataName]) 
== CreationPolicy.NonShared);

 

  MEF中提供了一個專門用於目錄過濾篩選的元數據特性PartMetadata,要進行目錄部件的篩選過濾就需要通過PartMetadata特性的標註,MEF容器才能進行正確的裝配。以一個簡單的實例演示,比如說有三個用戶控件(UserControl),分別進行導入和篩選過濾元數據的配置。

 

[PartMetadata("UC""AA")]
[Export(
typeof(UserControl))]
public partial class AA : UserControl
{
    
public AA()
    {
        InitializeComponent();
    }
}

[PartMetadata(
"UC""BB")]
[Export(
typeof(UserControl))]
public partial class BB : UserControl
{
    
public BB()
    {
        InitializeComponent();
    }
}

[PartMetadata(
"UC""CC")]
[Export(
typeof(UserControl))]
public partial class CC : UserControl
{
    
public CC()
    {
        InitializeComponent();
    }
}

 

 

  三個用戶控件的元數據名稱都爲"UC",其值分別是AA、BB、CC,那麼就可以通過下面代碼的方式實現對目錄中部件的篩選,下面是代碼塊演示瞭如何從目錄中篩選出元數據名稱爲"UC",其值爲"CC"的部件。

//獲取當前應用程序目錄
var catalog = new AssemblyCatalog(typeof(MainPage).Assembly);
//將目錄裝載進MEF組合容器
var parent = new CompositionContainer(catalog);
//通過元數據過濾篩選出元數據名稱爲"UC"值爲"CC"的組合部件
var filteredCat = new FilteredCatalog(catalog,
    def 
=> def.Metadata.ContainsKey("UC"&&
    def.Metadata[
"UC"].ToString() == "CC");
var perRequest 
= new CompositionContainer(filteredCat, parent);
var control 
= perRequest.GetExportedValue<UserControl>();

 

 

  本篇就介紹到這裏,詳細可下載本篇的源代碼進行測試演習,歡迎大家拍磚~~~~~~~~

  

  本篇參考於:Filtered Catalogs

  MEF官方網站:http://mef.codeplex.com/

  推薦指南:MEF程序設計指南一:在應用程序中宿主MEF

         MEF程序設計指南二:Silverlight中使用CompositionInitializer宿主MEF

         MEF程序設計指南三:MEF中組合部件(Composable Parts)與契約(Contracts)的基本應用

       MEF程序設計指南四:使用MEF聲明導出(Exports)與導入(Imports)

            MEF程序設計指南五:遲延(Lazy)加載導出部件(Export Part)與元數據(Metadata)

        MEF程序設計指南六:MEF中的目錄服務(DeploymentCatalog)

 

 

 

發佈了110 篇原創文章 · 獲贊 3 · 訪問量 32萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章