天天看點

Windows phone 應用開發[7]-MEF For Windows phone

在開始介紹之前如果你對MEf For Windows phone 中使用存在問題和相關的技術瓶頸 想了解一番可以閱讀如下文章:

MEf For Windows phone By damonpayne:

<a href="http://www.damonpayne.com/post/2010/06/25/MEF-for-Windows-Phone-7.aspx">http://www.damonpayne.com/post/2010/06/25/MEF-for-Windows-Phone-7.aspx</a>

<a target="_blank" href="http://blog.51cto.com/attachment/201201/132403474.png"></a>

MSAF分别針對原ComponentModel和Composition.Initialization空間做了Windows phone 類庫的移植. 而如上類庫正是MEF的核心.MSAF架構主要作用是提供了一種标準方法在Windows phone應用程式中添加對使用情況加以跟蹤并支援第三方資料分析的功能.這個我會下篇中Windows phone采集使用者資料和行為分析上講解.

Well 似乎MEF支援問題就如此意外的迎刃而解了.如下來做一個簡單執行個體來驗證.現在提出一個簡單需求我們宿主程式中要通過MEF方式內建一個管理分類的元件.元件和Windows phone宿主程式關系如下:

<a target="_blank" href="http://blog.51cto.com/attachment/201201/132410397.png"></a>

以建立一個Windows phone的類庫形式來實作這個元件 建立類庫并命名-MEFCommon.Data.首先添加MEF 類庫的引用:

<a target="_blank" href="http://blog.51cto.com/attachment/201201/132419464.png"></a>

分别引用了元MSAF源碼中System.ComponentModel和Composition.Initialization兩個DLL.建立一個封裝元件分類操作的接口IAppCatalog 添加引用如下:

using System.ComponentModel;     

using System.ComponentModel.Composition;     

using System.ComponentModel.Composition.Hosting; 

public interface IAppCatalog     

 {     

    bool AddCatalog(AppCatalog newAppCatalog);     

    List&lt;AppCatalog&gt; GetAllAppCatalogList();     

 } 

同時在該類以IAppCatalog接口作為契約名向MEF開放.該類一方面提供分類的全部資料同時能夠執行添加分類的操作.如下我們要在一個Windows phone宿主程式中用到分類元件提供分類資料.綁定UI上顯示,定義一個UI上可操作的ViewModel:

public class AppCatalog_ViewModel:BasicViewModel     

{     

    public AppCatalog_ViewModel()     

    {     

        CompositionInitializer.SatisfyImports(this);     

    }     

    public ObservableCollection&lt;AppCatalog&gt; appCatalogCollection = new ObservableCollection&lt;AppCatalog&gt;();     

    public ObservableCollection&lt;AppCatalog&gt; AppCatalogCollection    

     {    

         get { return this.appCatalogCollection; }    

         set    

         {    

             this.appCatalogCollection = value;    

             base.NotifyPropertyChangedEventHandler("AppCatalogCollection");    

         }    

     }    

     [Import(typeof(IAppCatalog))]    

     public IAppCatalog CurrentCatalogData { get; set; }    

     public void LoadAppCatalogData()    

         if (this.CurrentCatalogData != null)    

             if (this.CurrentCatalogData.GetAllAppCatalogList().Count &gt; 0)    

             {    

                 var catalogList = this.CurrentCatalogData.GetAllAppCatalogList();    

                 this.appCatalogCollection.Clear();    

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

             }    

首先在ViewModel定義一個以Import辨別IAppcatalog類型屬性用來接收元件中通過MEF需要傳遞的資料.其實這就是宿主程式一個擴充點.同樣這個Windows phone宿主程式需要添加對元件類庫和MEF 引用.現在有了元件的資料 和宿主程式的擴充點接入.Well,要實作元件與宿主程式之間通信則需要通過MEF建立組合的關聯關系. 而這個組合關系引用需要在應用程式啟動是調用.上篇中我們采用是一個Console應用程式直接寫在Main方法.作為Windows phone當然也可以直接寫在Launching和Activated事件中.當然最好的方式是建立一個實作IApplicationService接口的應用程式服務.可以獲得更好的代碼封裝和關注分離的效果 建立Service如下:

public class MEFAppCatalogService:IApplicationService     

    public MEFAppCatalogService()     

        CompositionHost.Initialize     

            (new AssemblyCatalog(Application.Current.GetType().Assembly),     

             new AssemblyCatalog(typeof(MEFCommon.Data.IAppCatalog).Assembly));     

     public void StartService(ApplicationServiceContext context) {   }    

     public void StopService() {  }    

接着指定運作的位置.向App.xaml内Application.ApplicationLifetimeObjects集合添加一個MEFAppCatalogService執行個體.則宿主程式會在任何應用程式代碼運作之前調用服務的Initialize方法來初始化MEF的管理容器.

&lt;Application.ApplicationLifetimeObjects&gt;     

    &lt;!--Required object that handles lifetime events for the application--&gt;     

    &lt;shell:PhoneApplicationService      

        Launching="Application_Launching" Closing="Application_Closing"      

        Activated="Application_Activated" Deactivated="Application_Deactivated"/&gt;     

    &lt;mef:MEFAppCatalogService&gt;&lt;/mef:MEFAppCatalogService&gt;     

&lt;/Application.ApplicationLifetimeObjects&gt; 

最後就是通過在ViewModel夠着方法中調用CompositionInitializer對象的SatisfyImports()方法實作填充指定元件的導入.[observerCollection集合已經綁定UIlistBox控件:

//元件導入     

CompositionInitializer.SatisfyImports(this); 

現在運作Windows phone應用程式看分類元件提供分類資料能拿到:

<a target="_blank" href="http://blog.51cto.com/attachment/201201/132426446.png"></a>

ok.成功通過MEF架構宿主程式自動感覺的靈活方式添加元件并獲得元件提供分類資料.證明MASF提供MEF類庫是可行的.到這了不禁有人會問相對上篇難道沒有其他方式建立宿主群組件之間組合關系?答案是肯定的.

隻不過如果我們不以Service形式.我們建立元件關系.這段建立組合關系代碼放在那? 應該采用什麼方式來組合? 來看看Mainpage綁定ViewModel時:

//Bind ViewModel     

private AppCatalog_ViewModel appcatalog_ViewModel = null;     

void MainPage_Loaded(object sender, RoutedEventArgs e)     

    if (this.appcatalog_ViewModel == null)     

        this.appcatalog_ViewModel = new AppCatalog_ViewModel();     

    this.appcatalog_ViewModel.LoadAppCatalogData();     

    this.DataContext = appcatalog_ViewModel;     

//顯示建立關聯關系     

AggregateCatalog mefCatalog = new AggregateCatalog();     

mefCatalog.Catalogs.Add(new AssemblyCatalog(Application.Current.GetType().Assembly));     

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

CompositionContainer mefContainer = new CompositionContainer(mefCatalog);     

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檔案見附件。

參考資料:

<a target="_blank" href="http://www.damonpayne.com/post/2010/06/25/MEF-for-Windows-Phone-7.aspx">MEF For Windows phone 7 By DAmon Payne</a>

<a target="_blank" href="https://github.com/mefcontrib">MEF Contrib [Github]</a>

<a target="_blank" href="http://msaf.codeplex.com/">Microsoft Silverlight Analyics FrameWork Codeplex</a>

可見每次都會Load時重新構造并調用ViewModel構造方法.考慮可以把組合關系代碼放在這.CompositionInitializer對象提供了對MEF容器的靜态方法控制.當然我們也可以像上篇一樣顯示的定義一個CompositionContainer 容器的方式直接管理. 可以把原ViewModel中代碼替換成:

建立AppCatalogOperator類實作該接口:

[Export(typeof(IAppCatalog))]     

public class AppCatalogOperator:IAppCatalog     

    public List&lt;AppCatalog&gt; OperatorCatalogList = new List&lt;AppCatalog&gt;();     

    public bool AddCatalog(AppCatalog newAppCatalog)     

        //No Check Reply     

        if(newAppCatalog!=null)    

            this.OperatorCatalogList.Add(newAppCatalog);    

         return true;    

     public List&lt;AppCatalog&gt; GetAllAppCatalogList()    

         this.OperatorCatalogList.Clear();    

         this.OperatorCatalogList.Add(new AppCatalog() { CatalogName = "Music+Video", CatalogNote = "Important for Common User" });    

         this.OperatorCatalogList.Add(new AppCatalog() { CatalogName = "Game", CatalogNote = "Different Kind of Game platform" });    

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

         return this.OperatorCatalogList;    

接口中分别定義兩個操作方法.一個用來添加分類方法 另外一個擷取所有分類的資料方法:

這篇文章中作者Damonpayne很詳細闡述了MEF 發展的過程以及相對Windows phone 開發不支援的一些相關特性類似:System.Reflection.Emit剔除. 針對MEF操作同樣也不支援IQueryable接口的類Linq操作等.并提出自己的一套在Windows phone 中使用MEF的解決方案.可惜的是作者直接給一個封裝不完整DLL.并删除下載下傳頁面.經過實際代碼嘗試Damonpayne給出的一條DeadWay.

<a href="http://down.51cto.com/data/2359661" target="_blank">附件:http://down.51cto.com/data/2359661</a>

本文轉自chenkaiunion 51CTO部落格,原文連結:http://blog.51cto.com/chenkai/763227