使用目錄(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 { get; set; }
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>();
本篇就介紹到這裡,詳細可下載本篇的源代碼進行測試演習,歡迎大家拍磚~~~~~~~~
文章出處:http://beniao.cnblogs.com/
本文配套源碼