您的位置:首页 > 其它

Windows phone 应用开发[7]-MEF For Windows phone

2011-12-28 19:41 316 查看
本篇是接着上篇Windowsphone应用开发[6]-ManagedExtensibilityFramework应用程序扩展基础之上而来.关于ManagedExtensibilityFrameWork[MEf]基础概念这里不再赘述.MEF作为.NET4一部分.同时也支持Silverlight4版本.但因目前官方并没有推出ManagedExtensibilityFrameworkForWindowsphone版本.对Codeplexhttp://mef.codeplex.com/上类库并不支持Windowsphone.这里介绍另外一种方式在Windowsphone中使用MEF.并以一个简单实例抛砖引玉.

在开始介绍之前如果你对MEfForWindowsphone中使用存在问题和相关的技术瓶颈想了解一番可以阅读如下文章:

MEfForWindowsphoneBydamonpayne:

http://www.damonpayne.com/post/2010/06/25/MEF-for-Windows-Phone-7.aspx

这篇文章中作者Damonpayne很详细阐述了MEF发展的过程以及相对Windowsphone开发不支持的一些相关特性类似:System.Reflection.Emit剔除.针对MEF操作同样也不支持IQueryable接口的类Linq操作等.并提出自己的一套在Windowsphone中使用MEF的解决方案.可惜的是作者直接给一个封装不完整DLL.并删除下载页面.经过实际代码尝试Damonpayne给出的一条DeadWay.

而欣慰的总是有人在无意间给你额外的惊喜.在我看MicrosoftSilverlightAnalyticsFramework[MSAF]源码时意外的发现.这个开源框架中尽然移植一个Windowsphone版本的MEF:



MSAF分别针对原ComponentModel和Composition.Initialization空间做了Windowsphone类库的移植.而如上类库正是MEF的核心.MSAF框架主要作用是提供了一种标准方法在Windowsphone应用程序中添加对使用情况加以跟踪并支持第三方数据分析的功能.这个我会下篇中Windowsphone采集用户数据和行为分析上讲解.

Well似乎MEF支持问题就如此意外的迎刃而解了.如下来做一个简单实例来验证.现在提出一个简单需求我们宿主程序中要通过MEF方式集成一个管理分类的组件.组件和Windowsphone宿主程序关系如下:



以创建一个Windowsphone的类库形式来实现这个组件创建类库并命名-MEFCommon.Data.首先添加MEF类库的引用:



分别引用了元MSAF源码中System.ComponentModel和Composition.Initialization两个DLL.创建一个封装组件分类操作的接口IAppCatalog添加引用如下:

usingSystem.ComponentModel;


[code]usingSystem.ComponentModel.Composition;

usingSystem.ComponentModel.Composition.Hosting;

[/code]

.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}

接口中分别定义两个操作方法.一个用来添加分类方法另外一个获取所有分类的数据方法:

publicinterfaceIAppCatalog


[code]{

boolAddCatalog(AppCatalognewAppCatalog);


List<AppCatalog>GetAllAppCatalogList();


}

[/code]

.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}

创建AppCatalogOperator类实现该接口:

[Export(typeof(IAppCatalog))]


[code]publicclassAppCatalogOperator:IAppCatalog

{


publicList<AppCatalog>OperatorCatalogList=newList<AppCatalog>();




publicboolAddCatalog(AppCatalognewAppCatalog)


{


//NoCheckReply


if(newAppCatalog!=null)


this.OperatorCatalogList.Add(newAppCatalog);


returntrue;


}




publicList<AppCatalog>GetAllAppCatalogList()


{


this.OperatorCatalogList.Clear();


this.OperatorCatalogList.Add(newAppCatalog(){CatalogName="Music+Video",CatalogNote="ImportantforCommonUser"});


this.OperatorCatalogList.Add(newAppCatalog(){CatalogName="Game",CatalogNote="DifferentKindofGameplatform"});


this.OperatorCatalogList.Add(newAppCatalog(){CatalogName="Book",CatalogNote="Reader"});




returnthis.OperatorCatalogList;




}


}

[/code]

.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}

同时在该类以IAppCatalog接口作为契约名向MEF开放.该类一方面提供分类的全部数据同时能够执行添加分类的操作.如下我们要在一个Windowsphone宿主程序中用到分类组件提供分类数据.绑定UI上显示,定义一个UI上可操作的ViewModel:


publicclassAppCatalog_ViewModel:BasicViewModel


[code]{

publicAppCatalog_ViewModel()


{


CompositionInitializer.SatisfyImports(this);


}




publicObservableCollection<AppCatalog>appCatalogCollection=newObservableCollection<AppCatalog>();


publicObservableCollection<AppCatalog>AppCatalogCollection


{


get{returnthis.appCatalogCollection;}


set


{


this.appCatalogCollection=value;


base.NotifyPropertyChangedEventHandler("AppCatalogCollection");


}


}




[Import(typeof(IAppCatalog))]


publicIAppCatalogCurrentCatalogData{get;set;}




publicvoidLoadAppCatalogData()


{


if(this.CurrentCatalogData!=null)


{


if(this.CurrentCatalogData.GetAllAppCatalogList().Count>0)


{


varcatalogList=this.CurrentCatalogData.GetAllAppCatalogList();


this.appCatalogCollection.Clear();


catalogList.ForEach(x=>{this.appCatalogCollection.Add(x);});


}


}


}


}

[/code]

.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}

首先在ViewModel定义一个以Import标识IAppcatalog类型属性用来接收组件中通过MEF需要传递的数据.其实这就是宿主程序一个扩展点.同样这个Windowsphone宿主程序需要添加对组件类库和MEF引用.现在有了组件的数据和宿主程序的扩展点接入.Well,要实现组件与宿主程序之间通信则需要通过MEF建立组合的关联关系.而这个组合关系引用需要在应用程序启动是调用.上篇中我们采用是一个Console应用程序直接写在Main方法.作为Windowsphone当然也可以直接写在Launching和Activated事件中.当然最好的方式是创建一个实现IApplicationService接口的应用程序服务.可以获得更好的代码封装和关注分离的效果创建Service如下:


publicclassMEFAppCatalogService:IApplicationService


[code]{

publicMEFAppCatalogService()


{


CompositionHost.Initialize


(newAssemblyCatalog(Application.Current.GetType().Assembly),


newAssemblyCatalog(typeof(MEFCommon.Data.IAppCatalog).Assembly));


}




publicvoidStartService(ApplicationServiceContextcontext){}




publicvoidStopService(){}


}

[/code]

.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}

在构造方法中.调用CompositionHost对象Initialize()方法.相对于上篇我们直接通过定义CompositionContainer容器的方式.而目前CompositionHost对象提供用于控制CompositionInitializer所使用的容器的静态方法.二者效果是一致的.Initialize()方法在构造是可以接受任意数量的目录.这和AggregateCatalog对象指定MEF解析范围是一致的.目录适用于定义MEF在解析类型是需要检索的位置范围.而引用的对象AssemblyCatalog则分别提供对分类组件类库和宿主应用程序的静态引用.

接着指定运行的位置.向App.xaml内Application.ApplicationLifetimeObjects集合添加一个MEFAppCatalogService实例.则宿主程序会在任何应用程序代码运行之前调用服务的Initialize方法来初始化MEF的管理容器.


<Application.ApplicationLifetimeObjects>


[code]<!--Requiredobjectthathandleslifetimeeventsfortheapplication-->

<shell:PhoneApplicationService


Launching="Application_Launching"Closing="Application_Closing"


Activated="Application_Activated"Deactivated="Application_Deactivated"/>




<mef:MEFAppCatalogService></mef:MEFAppCatalogService>


</Application.ApplicationLifetimeObjects>

[/code]

.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}

最后就是通过在ViewModel够着方法中调用CompositionInitializer对象的SatisfyImports()方法实现填充指定组件的导入.[observerCollection集合已经绑定UIlistBox控件]:

//组件导入


[code]CompositionInitializer.SatisfyImports(this);
[/code]

.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}

现在运行Windowsphone应用程序看分类组件提供分类数据能拿到:



ok.成功通过MEF框架宿主程序自动感知的灵活方式添加组件并获得组件提供分类数据.证明MASF提供MEF类库是可行的.到这了不禁有人会问相对上篇难道没有其他方式建立宿主和组件之间组合关系?答案是肯定的.

只不过如果我们不以Service形式.我们建立组件关系.这段建立组合关系代码放在那?应该采用什么方式来组合?来看看Mainpage绑定ViewModel时:


//BindViewModel


[code]privateAppCatalog_ViewModelappcatalog_ViewModel=null;

voidMainPage_Loaded(objectsender,RoutedEventArgse)


{


if(this.appcatalog_ViewModel==null)


this.appcatalog_ViewModel=newAppCatalog_ViewModel();


this.appcatalog_ViewModel.LoadAppCatalogData();


this.DataContext=appcatalog_ViewModel;


}

[/code]

.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}

可见每次都会Load时重新构造并调用ViewModel构造方法.考虑可以把组合关系代码放在这.CompositionInitializer对象提供了对MEF容器的静态方法控制.当然我们也可以像上篇一样显示的定义一个CompositionContainer容器的方式直接管理.可以把原ViewModel中代码替换成:




[code]//显示建立关联关系

AggregateCatalogmefCatalog=newAggregateCatalog();


mefCatalog.Catalogs.Add(newAssemblyCatalog(Application.Current.GetType().Assembly));


mefCatalog.Catalogs.Add(newAssemblyCatalog(typeof(MEFCommon.Data.IAppCatalog).Assembly));




CompositionContainermefContainer=newCompositionContainer(mefCatalog);


mefContainer.ComposeParts(this);

[/code]

.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}

通过AggregateCAtalog显示指定MEF解析类型需要检索的位置范围。编译运行发现效果是一致的.

关于这两种方式.最简洁使用就是CompositionInitializer对象提供静态控制.把更多的工作交给MEF自身去做.另外一个好处就是可以随时随地在程序中添加MEF组合关系和检索位置的范围.这是显示定义CompositionContainer容器方式所无法直接做到的.

Well关于MEF终于历经多次验证终于能够成功运行在Windowsphone应用程序中.本篇只是介绍简单使用方法.目的是抛砖引玉.体现MEF也能够在Windowsphone扩展组件能力和灵活的方式都值得我们在实际项目加以实践.算是提出MEF在Windowsphone中使用一种解决方案.如果任何问题请在评论中提出.如下会给出本篇实例源码和MASFMEFForwindowsphone版本的DLL.

本篇实例代码:/Files/chenkai/MEFSampleDemo.rar

MEFForwindowsPhoneDLL文件:/Files/chenkai/ComponentModelDLL.rar

参考资料:

MEFForWindowsphone7ByDAmonPayne

MEFContrib[Github]

MicrosoftSilverlightAnalyicsFrameWorkCodeplex
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
章节导航