如果不使用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
>
();
本篇就介绍到这里,详细可下载本篇的源代码进行测试演习,欢迎大家拍砖~~~~~~~~
本篇参考于: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)