本篇是接着上篇Windows phone 应用开发[6]-Managed Extensibility Framework应用程序扩展 基础之上而来. 关于Managed Extensibility FrameWork[MEf]基础概念这里不再赘述.MEF 作为.NET 4一部分.同时也支持Silverlight4 版本.但因目前官方并没有推出Managed Extensibility Framework For Windows phone 版本. 对Codeplexhttp://mef.codeplex.com/上类库并不支持Windows phone. 这里介绍另外一种方式在Windows phone 中使用MEF.并以一个简单实例 抛砖引玉.

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

MEf For Windows phone By damonpayne:

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

 

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

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

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

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

 
  
  1. using System.ComponentModel;     
  2. using System.ComponentModel.Composition;     
  3. using System.ComponentModel.Composition.Hosting; 

 

 
  
  1. public interface IAppCatalog     
  2.  {     
  3.     bool AddCatalog(AppCatalog newAppCatalog);     
  4.     List<AppCatalog> GetAllAppCatalogList();     
  5.  } 

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

 

 
  
  1. public class AppCatalog_ViewModel:BasicViewModel     
  2. {     
  3.     public AppCatalog_ViewModel()     
  4.     {     
  5.         CompositionInitializer.SatisfyImports(this);     
  6.     }     
  7.  
  8.     public ObservableCollection<AppCatalog> appCatalogCollection = new ObservableCollection<AppCatalog>();     
  9.     public ObservableCollection<AppCatalog> AppCatalogCollection    
  10.      {    
  11.          get { return this.appCatalogCollection; }    
  12.          set    
  13.          {    
  14.              this.appCatalogCollection = value;    
  15.              base.NotifyPropertyChangedEventHandler("AppCatalogCollection");    
  16.          }    
  17.      }    
  18.  
  19.      [Import(typeof(IAppCatalog))]    
  20.      public IAppCatalog CurrentCatalogData { get; set; }    
  21.  
  22.      public void LoadAppCatalogData()    
  23.      {    
  24.          if (this.CurrentCatalogData != null)    
  25.          {    
  26.              if (this.CurrentCatalogData.GetAllAppCatalogList().Count > 0)    
  27.              {    
  28.                  var catalogList = this.CurrentCatalogData.GetAllAppCatalogList();    
  29.                  this.appCatalogCollection.Clear();    
  30.                  catalogList.ForEach(x => { this.appCatalogCollection.Add(x); });    
  31.              }    
  32.          }    
  33.      }    
  34.  } 

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

 
  
  1. public class MEFAppCatalogService:IApplicationService     
  2. {     
  3.     public MEFAppCatalogService()     
  4.     {     
  5.         CompositionHost.Initialize     
  6.             (new AssemblyCatalog(Application.Current.GetType().Assembly),     
  7.              new AssemblyCatalog(typeof(MEFCommon.Data.IAppCatalog).Assembly));     
  8.     }     
  9.  
  10.      public void StartService(ApplicationServiceContext context) {   }    
  11.  
  12.      public void StopService() {  }    
  13.  } 

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

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

 
  
  1. <Application.ApplicationLifetimeObjects>     
  2.     <!--Required object that handles lifetime events for the application-->     
  3.     <shell:PhoneApplicationService      
  4.         Launching="Application_Launching" Closing="Application_Closing"      
  5.         Activated="Application_Activated" Deactivated="Application_Deactivated"/>     
  6.          
  7.     <mef:MEFAppCatalogService></mef:MEFAppCatalogService>     
  8. </Application.ApplicationLifetimeObjects> 

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

 
  
  1. //组件导入     
  2. CompositionInitializer.SatisfyImports(this); 

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

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

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

 
  
  1. //Bind ViewModel     
  2. private AppCatalog_ViewModel appcatalog_ViewModel = null;     
  3. void MainPage_Loaded(object sender, RoutedEventArgs e)     
  4. {     
  5.     if (this.appcatalog_ViewModel == null)     
  6.         this.appcatalog_ViewModel = new AppCatalog_ViewModel();     
  7.     this.appcatalog_ViewModel.LoadAppCatalogData();     
  8.     this.DataContext = appcatalog_ViewModel;     

 

 
  
  1. //显示建立关联关系     
  2. AggregateCatalog mefCatalog = new AggregateCatalog();     
  3. mefCatalog.Catalogs.Add(new AssemblyCatalog(Application.Current.GetType().Assembly));     
  4. mefCatalog.Catalogs.Add(new AssemblyCatalog(typeof(MEFCommon.Data.IAppCatalog).Assembly));     
  5.  
  6. CompositionContainer mefContainer = new CompositionContainer(mefCatalog);     
  7. mefContainer.ComposeParts(this); 

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

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

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

本篇实例代码见附件。

MEF For windows Phone DLL文件见附件。

 

参考资料:

MEF For Windows phone 7 By DAmon Payne

MEF Contrib [Github]

Microsoft Silverlight Analyics FrameWork Codeplex

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

创建AppCatalogOperator类实现该接口:

 
  
  1. [Export(typeof(IAppCatalog))]     
  2. public class AppCatalogOperator:IAppCatalog     
  3. {     
  4.     public List<AppCatalog> OperatorCatalogList = new List<AppCatalog>();     
  5.  
  6.     public bool AddCatalog(AppCatalog newAppCatalog)     
  7.     {     
  8.         //No Check Reply     
  9.         if(newAppCatalog!=null)    
  10.             this.OperatorCatalogList.Add(newAppCatalog);    
  11.          return true;    
  12.      }    
  13.  
  14.      public List<AppCatalog> GetAllAppCatalogList()    
  15.      {    
  16.          this.OperatorCatalogList.Clear();    
  17.          this.OperatorCatalogList.Add(new AppCatalog() { CatalogName = "Music+Video", CatalogNote = "Important for Common User" });    
  18.          this.OperatorCatalogList.Add(new AppCatalog() { CatalogName = "Game", CatalogNote = "Different Kind of Game platform" });    
  19.          this.OperatorCatalogList.Add(new AppCatalog() { CatalogName = "Book", CatalogNote = "Reader" });    
  20.  
  21.          return this.OperatorCatalogList;    
  22.  
  23.      }    
  24.  } 

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

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

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