Composite UI Application Block開發的介紹

 

完成本實驗之後,您能夠:

·         瞭解Composite UI Application Block。

·         使用Composite UI Application Block 的Module Loading特性。

·         瞭解推薦的項目佈局和代碼結構。

 

場景

您將要集中瞭解Composite UI Application Block的目的與特性,以及在開發應用程序時如何使用這個應用程序構造塊。

練習1: Composite UI Application Block的概念與特性

在本練習中,您將瞭解到Composite UI Application Block的組成部分,及其相關的概念。接下來的練習重點則是使用Microsoft Visual Studio 2005開發系統和.NET Compact Framework 2.0版來實現這些概念。

介紹

Composite UI Application Block被設計用於構造基於Windows窗體的複雜應用程序。爲此,它提供了一套體系結構和實現方案,這個方案使用了在前端, Line–Of-Business(LOB)應用程序中創建的通用模式。使用Composite UI Application Block構建應用程序有以下好處:

·         對體系結構團隊來說,能夠改善質量和一致性;

·         對於大型開發團隊來說,能夠提高生產率,縮短產品開發週期;

·         對於操作人員,能夠鞏固操作結果。

這個應用程序構造塊被設計來開發用於移動設備的商務線應用程序的智能客戶端。

設計概述。

通過使用獨立而相互協作的模塊來支持應用程序開發,是Composite UI Application Block的主要設計目標之一。Composite UI Application Block應用程序可以包含以下組件:

·         SmartParts

SmartParts給出了應用程序中的可視元素。這些可視元素與控制它們的應用程序完全獨立,可以完全獨立的開發。

·         Workspace

Workspace是SmartPart的容器與管理器。它可以控制SmartPart如何顯示或者隱藏,以及如何佈局。可以創建並使用以下類型的Workspaces:

¡   TabWorkspace:讓您在選項頁中顯示或隱藏控件和SmartParts;

¡   DeckWorkspace:讓您在不可見的框架中以層迭的方式顯示或隱藏控件和SmartParts。其IWorkspace方法使用類似卡片組的方式實現SmartParts的顯示、隱藏和關閉。顯示SmartPart使得它在以前顯示的SmartPart上面出現。隱藏SmartPart使除它之外最上面的一個SmartPart顯示。關閉SmartPart將它刪除,並顯示除它之外最上面的一個SmartPart。

·         WorkItems

WorkItem是運行時組件的容器,與組件相互協作以完成一個用例。它包括以下代碼和類:

¡   初始化用例的啓動(或者初始化)代碼;

¡   用例中協作的組件共享的狀態;

¡   根據狀態和其他資源產生行爲的Controller類;

¡   與相應Controller和引用的狀態進行交互的View類;

¡   釋放資源的代碼。

·         Infrastructure Services(基礎架構服務)

Composite UI Application Block包含一套底層的基礎架構服務,可以在應用程序中使用。您也可以根據您的應用程序構建自己的服務來提供基礎架構的能力。應用程序構造塊提供以下基礎架構服務:

¡   Catalog Reader;

¡   Module Loader;

¡   Event Broker;

¡   Commands。

·         Modules

該模塊由一系列服務、WorkItems、SmartParts、控件、商務實體和Module Initialization類組成,其中Module Initialization類用於初始化和運行該模塊的WorkItems。

·         Module Services

該模塊服務是對象,使用Service屬性註冊一次之後,就可以從任一WorkItem的其他組件中引用它。

·         State

WorkItem包含狀態,它是一個鬆散類型的對象集合,這些對象由該用例中協作的組件共享。狀態可以通過調用WorkItem的Load和Save方法進行維持。可以使用實現IStatePersistenceService的基礎架構服務在任一存儲介質上維持狀態。

·         Controllers/Presenters

在MVC和MVP模式中,控制器和表示器分別具有同樣的角色。

·         Service Agents

服務代理是用於與外部後端服務進行交互的組件。

當您開發的應用程序要使用外部服務時,使用服務代理就是必要的;所以在這裏作爲重要組件列出。然而,CAB卻並沒有爲這些組件提供任何正式的結構或者支持。

Composite UI Application Block由一些子系統組成,它們通過互操作提供這個應用程序塊對外提供的功能。這些子系統都在自己的命名空間和程序集中定義,如下圖所示。

在典型的CAB實現中,會使用到以下程序集:

·         Microsoft.Practices.CF.CompositeUI.WinForms.dll;

·         Microsoft.Practices.CF.CompositeUI.dll;

·         Microsoft.Practices.CF.ObjectBuilder.dll。

 

 

練習2: 創建一個模塊

在本練習中,創建一個基礎模塊,只包含一個服務和一個WorkItem。

第一步

雙擊打開桌面上的ModuleLoader.sln文件,並生成該解決方案。

設置環境

1.      在視圖中展開所有的項目和文件夾,熟悉一下Visual Studio 2005中新的Solution Explorer。

特別檢查一下Services、WorkItems和Views文件夾和結構。在使用CAB開發應用程序時,這是組織和佈局您的解決方案和項目的一種方法。您在每個模塊自己的.NET類庫項目中編寫程序(並且各模塊分別編譯爲一個程序集)。所有的服務、WorkItems和Views都分別在自己的文件夾中。ModuleInit類在根目錄下,保存一個初始化該模塊的類。

您可以看到一個淡黃色,名叫CAB的文件夾。這是微軟引入IDE的一種新特性,叫做解決方案文件夾。這些文件夾用於分組這些項目和解決方案項目,以便能夠更好的管理和查看這些解決方案。CAB文件夾包含Composite UI Application Block的這三個子系統。

注意,您需要關注兩個項目:ModuleLoaderShell和GPSModule。

ModuleLoaderShell項目包含應用程序的入口點和Workspaces。GPSModule是組成所要創建模塊的結構體。確保在項目屬性的Device選項卡中,GPSModule的輸出文件的文件夾字段的值和ModuleLoaderShell程序集保持一致;並且對於ModuleLoaderShell和GPSModule,在解決方案屬性(右鍵點擊解決方案->屬性)的配置屬性節點中Deploy複選框是選中的。

2.      在GPSModule項目下展開References節點。

您可以看到這四個CAB子系統(Mobile.CompositeUI、Configuration、Mobile.ObjectBuilder和Mobile.CompositeUI.WinForms)的引用。設置每個引用的Copy Local屬性爲true,這樣,在編譯該解決方案(包括子系統)時,這些程序集將被拷貝到本地的模塊與外殼的調試目錄下。

生成您的第一個模塊

1.      展開Services文件夾,打開IGPSService.cs和GPSService.cs文件。

模塊可以包含多個不同的元素。在本練習中,所創建的模塊有兩個服務,一個視圖和一個驅動服務和視圖的WorkItem。

2.      在IGPSService.cs文件中標識的位置粘貼如下代碼。

public interface IGPSService

{

int GetLatitude();

int GetLongitude();

}

創建服務的第一步是要創建定義服務操作或者方法的接口。在本練習中,所申明的服務有兩個主要的操作:GetLatitude和GetLongitude。使用接口來定義服務,因爲這樣您可以很容易改變操作的實現,同時又不影響其他部分的基礎代碼。

3.      在GPSService.cs文件中標識的位置粘貼以下服務實現代碼。

[Service(typeof(IGPSService))]

public class GPSService : IGPSService

{

public int GetLatitude()

{

return 42;

}

public int GetLongitude()

{

return 125;

}

}

這是服務創建中很重要的一部分。它實際實現您通過IGPSService接口定義的服務。您創建了一個名爲GPSService的類,它實現IGPSService接口。然後,需要爲您的兩個操作編寫實現代碼:GetLatitude和GetLongitude。在實現方法中,僅僅各自返回一個虛擬的值。然而,有的時候,您可能想要重新編寫這個服務的實現,真正連接到GPS接收器上,獲取實時的位置信息。

您會看到這段代碼和普通的接口實現代碼有些不同,首先就是在類的上面使用了Service屬性。這個屬性用於將這個類註冊爲當前模塊的服務。這樣,CAB才能夠輕易得定位到服務的實現,並在必要的時候使用它們。這裏,您把ServiceType設置爲IGPSService接口的類型,通過這種方式,您可以輕易的改變代碼實現,而不會影響到那些需要引用該服務的代碼。

4.      打開Services文件夾下面的OnDemandService.cs文件。在第一個“//TODO”標識下面粘貼以下代碼。

public interface IDistanceCalculatorService

{

int ComputeDistance(int latitude, int longitude);

}

這裏,您創建了另一個名爲IDistanceCalculatorService的服務,它有一個操作,通過經度和緯度的值,計算距離。

5.      在第二個“//TODO”標識下面粘貼以下代碼。

[Service(typeof(IDistanceCalculatorService), AddOnDemand = true)]

public class DistanceCalculatorService : IDistanceCalculatorService

{

public DistanceCalculatorService()

{

MessageBox.Show("This is DistanceCalculatorService being constructed
for the first time.\nSubsequent calls to the service will not require construction.",

"Service constructed",

MessageBoxButtons.OK,

MessageBoxIcon.None,

MessageBoxDefaultButton.Button1);

}

 

public int ComputeDistance(int latitude, int longitude)

{

return 1234;

}

}

6.      這一次,您編寫的是IDistanceCalculatorService的實現。您還編寫了一個構造函數,當服務被構造和初始化時,會彈出對話框提醒您。

7.      這第二個服務引入了一個叫做On Demand Services的特性。使用On Demand Services特性實現的服務,直到實際請求使用時,纔會被實例化。要使用On Demand Services特性,需要添加AddOnDemand屬性,並設置其值爲true。

不像其他服務那樣在模塊初始化時就被創建,on-demand的服務直到代碼定位到該服務纔會被創建。當您有很多服務的時候這種方法十分有用,因爲只有在需要使用服務的時候,纔會把它們裝載到內存中。例如,您可能會有200個服務,只有需要時才使用,這將節省很多內存,可以極大的改善性能。

8.      現在,服務都已經有了,您需要設置視圖來使用前一步實現的服務。

展開Views文件夾,右鍵點擊GPSView項,選擇View Code。

9.      您可以看到一個名叫GPSView的類,它是從UserControl繼承的。這和其他自定義的控件實現一樣。如果您不熟悉.NET Framework 2.0,您可能會對聲明部分的partial關鍵字感到陌生。而且,代碼中有對InitializeComponent方法的調用可是卻找不到InitializeComponent方法的定義。

.NET Framework 2.0的一個新特性允許您把一個類做成partial的。這樣,您可以在當前的代碼位置只編寫一部分實現代碼,而在其他位置編寫餘下的實現代碼。您可以把一個類的定義劃分爲多個源文件來實現。這可以幫助您消除混亂,在一個文件中實現UI的佈局,而在另一個文件中實現您的事件處理函數。例如,發送一個文件給創建前端程序的視圖設計員,而發送另一個文件給創建業務邏輯和事件處理代碼的業務邏輯開發人員。

在GPSView類的頭部,第一個標識 “//TODO”的地方,添加如下代碼。

private IGPSService gpsService;

 

[ServiceDependency]

public IGPSService GPS

{

set { gpsService = value; }

}

這部分代碼告訴CAB,這個類依賴於IGPSService。您沒有初始化一個新的服務。您要使用的是已經創建和存儲的服務。CAB使用Inversion of Control(IOC)或者Dependency Injection技術來實現該任務。當您在成員屬性中放置了[ServiceDependency]屬性後,當視圖添加到WorkItem時,將會自動完成對正確運行時要調用服務的初始化工作。

在您的視圖中要使用到GPS服務,所以就在這裏添加了依賴型。

10.    用以下代碼替換cmdGetDistance_Click方法。

private void cmdGetDistance_Click(object sender, EventArgs e)

{

// 注意,您沒有爲IDistanceCalculatorService添加ServiceDependencyAttribute,

// 因爲,這樣這個服務會在視圖添加到工作項時被創建。

// 這僅僅是爲了這個實例而已。

// 該服務直到這個方法被調用纔會被裝載到內存。

// 直到屬性被第一次調用,纔會應用[ServiceDependency]屬性。

 

IDistanceCalculatorService calc =parentWorkItem.Services.Get<IDistanceCalculatorService>();

txtDistance.Text = calc.ComputeDistance(

gpsService.GetLatitude(),

gpsService.GetLongitude()).ToString();

}

這段代碼是響應GetDistance按鈕的事件處理函數,點擊該按鈕可以查詢當前的距離。

要得到距離,需要用到IDistanceCalculatorService和GPSService。IdistanceCalculatorService已經定義爲了On Demand的服務,它直到現在纔會被構造。構造和定位這個服務,需要調用父工作項中Services集合的Get方法。Get方法得到您所要定位服務(IDistanceCalculatorService)的類型,並返回一個引用。

然後,您需要調用ComputeDistance方法來定位實際的距離,並將它存儲在視圖的txtDistance文本框中。ComputeDistance方法使用經度和緯度作爲參數;因此,您還需要調用GPSService的GetLatitude和GetLongitude方法來返回信息。

您不需要調用Services集合的Get方法來定位GPSService。這是因爲您使用了[ServiceDependency]屬性,當這個視圖被添加到WorkItem時,它會爲您調用Services.Get方法。

11.    用以下代碼替換cmdGetLatitude_Click方法。

private void cmdGetLatitude_Click(object sender, EventArgs e)

{

txtLatitude.Text = gpsService.GetLatitude().ToString();

}

這是響應GetLatitude按鈕的事件處理函數,用來從GPSService中獲取經度值。在前一步驟,調用了GPSService的GetLatitude方法,並將結果存儲在文本框中。您不必調用Services集合的Get操作,因爲您已經通過使用ServiceDependency屬性獲取了這個服務的一個實例。

12.    展開WorkItems文件夾,並打開GPSWorkItem.cs文件。

13.    用以下代碼替換OnRunStarted方法:

protected override void OnRunStarted()

{

base.OnRunStarted();

 

IWorkspace GPSWorkspace = Workspaces["mainWorkspace"];

GPSWorkspace.Show(Items.AddNew<GPSView>());

}

這個WorkItem的目的是在指定工作區顯示GPSView。

WorkItem是該體系結構中至關重要的一個部分,這裏說的是在外殼的workspace中顯示視圖的方法。

如果您對.NET framework 2.0還不熟悉,您可能會對以下語句產生疑惑。

Items.AddNew<GPSView>().

在平臺中引入了一種叫做Generics的新特性。您可以訪問以下網址,閱讀MSDN上的介紹文章以獲取更多關於Generics的信息:

http://msdn.microsoft.com/msdnmag/issues/06/00/NET/

AddNew調用只是把類型作爲模板參數接收,這說明它是什麼類型,用什麼類型工作。然後它將返回這個類型,而不是簡單的對象類型,這樣就不必做類型轉換了。

創建Shell

1.      如果還沒有展開ModuleLoaderShell項目,則將它展開,然後雙擊MainForm.cs項。

展示在您眼前的是新的Visual Studio 2005窗體開發環境。在窗體中,您可以看到一個TabWorkspace控件,名爲mainWorkspace。現在,您可以明白在上一步驟中GPSView被放到哪裏了。請查看上一步,您會發現您已經引用了這個mainWorkspace,控件,相關的語句是:

IWorkspace GPSWorkspace = Workspaces["mainWorkspace"];

2.      在Solution Explorer中,雙擊ProfileCatalog.xml文件以打開它。

Composite UI Application Block支持通過使用解決方案類別配置文件來自定義應用程序。解決方案配置文件提供一個模塊的列表,被裝載到應用程序中。

因爲您已經創建了一個模塊,並且希望在應用程序中使用,您必須在ProfileCatalog.xml文件中定義該模塊。這樣,模塊裝載器纔會裝載這個模塊。

3.      用以下代碼替換ProfileCatalog.xml中的XML內容:

<?xml version="1.0" encoding="utf-8" ?>

<SolutionProfile xmlns="http://schemas.microsoft.com/pag/cab-profile" >

<Modules>

<ModuleInfo AssemblyFile="GPSModule.dll"/>

</Modules>

</SolutionProfile>

研究一下格式:其實很簡單。您可以爲應用程序定義多個不同的解決方案配置文件,但是要記住,每個應用程序實際只能使用一個配置文件。您可以看到,在前面這個XML示例中,解決方案配置文件的名字是默認的。它是默認的配置文件,如果沒有在代碼中指定,使用的就是這個配置文件,而不是其它。

確保Copy To Output Directory屬性設置爲Copy always,否則,解決方案就不知道應該在哪裏去找這個類別文件。

每個解決方案配置文件可以有多個模塊,但是在這個例子中,您只有一個名爲GPSModule的模塊。

創建Program和根WorkItem

1.      在Solution Explorer中,雙擊Program.cs文件以打開它。

2.      用以下代碼替換Main方法。

[MTAThread]

static void Main()

{

new Program().Run();

}

這是這個應用程序的入口點。

調用這個類的Run方法。這個類實現了FormShellApplication<ShellWorkItem, MainForm>,並且給它傳入了要使用的工作項類型,以及作爲外殼要使用的窗體。

調用Run方法將會裝載ProfileCatalog.xml文件,並決定需要裝載哪個模塊。在獲取模塊列表之後,它會開始裝載這些模塊並對它們進行初始化。如果有模塊包含了ModuleInit類,將會構造這個類,並調用相應的Load和/或AddServices方法。

試運行程序

1.      要生成該應用程序,按Ctrl+Shift+B。

這將生成這個解決方案。修改生成過程中可能出現的錯誤,然後重複這個步驟,直到不再顯示任何錯誤。

2.      要以調試模式啓動該應用程序,按F5。

警告 模擬器明顯比實際設備要慢得多,所以在啓動應用程序的時候需要等一會。

而且,如果您還不能生成和調試該解決方案,請確保ModuleLoaderShell項目已經被設置爲Startup Project了。

如果在這個階段出現錯誤,請確保您的ProfileCatalog.xml文件是正確的。當出現Connect to Device窗口時,選擇Windows Mobile 5.0 Pocket PC Emulator並點擊Connect按鈕。

3.      當UI裝載完之後,模擬器中顯示的結果如下圖所示。

4.      點擊GPS Module標籤,如下圖所示。

 

5.      點擊“Get Distance”按鈕以初始化IDistanceCalculatorService服務,並調用ComputeDistance方法。

您會收到服務正在第一次被構造的確認信息。

6.      再次點擊“Get Distance”按鈕。這次將不會收到任何信息。

這說明代碼沒有試圖再次構造該服務。它只是簡單的返回存儲在根WorkItem中的服務。

7.      點擊“Get Latitude”按鈕,運行IGPSService服務中的GetLatitude方法。您不會收到任何消息,因爲IGPSService服務已經在應用程序啓動時被初始化了,這是因爲您並沒有爲它使用On Demand屬性。

8.      在Visual Studio 2005中點擊Stop按鈕,退出該應用程序。

 (完)


 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章