如果不使用MEF進行託管擴展處理,只有通過WebClient進行程序包的下載、解析。實際上MEF的動態下載的底層實現一樣是使用的WebClient,然後利用AggregateCatalog進行動態組合,詳細可查看MEF的源代碼(路徑:Composition.Initialization/System/ComponentModel/Composition/Hosting/DeploymentCatalog.cs)。
在上一篇程序設計指南《MEF程序設計指南六:MEF中的目錄服務(DeploymentCatalog)》中介紹了MEF的目錄服務,並對MEF的目錄服務進行了接口封裝,其中有一個接口就是專門封裝的使用MEF的目錄進行.xap程序包的動態裝載的。
{
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包的動態下載以及組合。
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容器中,此接口就會自動的得到通知。其內部就一個接口方法,詳細如下代碼塊:
{
}
在使用MEF目錄進行導出部件託管的時候,在某些需求下或許只需要其中的一個部件,這種情況可以通過遍歷部件集合得到。然而MEF也爲此提供了一種解決方案,那就是使用目錄過濾篩選功能。MEF中的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中的約定其篩選表達式應如下格式。
def => def.Metadata.ContainsKey(CompositionConstants.PartCreationPolicyMetadataName) &&
((CreationPolicy)def.Metadata[CompositionConstants.PartCreationPolicyMetadataName]) == CreationPolicy.NonShared);
MEF中提供了一個專門用於目錄過濾篩選的元數據特性PartMetadata,要進行目錄部件的篩選過濾就需要通過PartMetadata特性的標註,MEF容器才能進行正確的裝配。以一個簡單的實例演示,比如說有三個用戶控件(UserControl),分別進行導入和篩選過濾元數據的配置。
[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程序設計指南二:Silverlight中使用CompositionInitializer宿主MEF
MEF程序設計指南三:MEF中組合部件(Composable Parts)與契約(Contracts)的基本應用
MEF程序設計指南四:使用MEF聲明導出(Exports)與導入(Imports)
MEF程序設計指南五:遲延(Lazy)加載導出部件(Export Part)與元數據(Metadata)
MEF程序設計指南六:MEF中的目錄服務(DeploymentCatalog)