最近開發需要用到Smart Client Software Factory(SCSF)進行Smartclient的開發,SCSF其實是基於CAB和企業庫的一個軟件工廠開發工具包,核心就是CAB,所以瞭解SCSF其實就是需要對CAB進行了解,在網上找了些資料,放在這裏以便查閱:
文章引用:http://www.cnblogs.com/mixiaobo/archive/2008/01.html
微軟開發了一套開源的企業庫 (Enterprise Library),通過使用這套企業庫裏面提供的各種應用程序塊可以極大的提高應用程序的開發效率和縮短開發週期,也由此得到了大家的廣泛應用。
企業庫包括大家熟知的如下應用程序塊:
Caching Application Block.
Cryptography Application Block.
Data Access Application Block.
Exception Handling Application Block.
Logging Application Block.
Security Application Block.
Validation Application Block.
Policy Injection Application Block.
這些應用程序塊都是一些常用的非業務相關的公共模塊,相關資料在網上搜一下就一大堆,所以很多使用過企業庫的朋友應該並不陌生。所以這裏也就不再多說。
我今天要給大家介紹的其實也是一個應用程序塊,但是是獨立於企業庫單獨安裝的。網上也能搜到一些相關資料,但總覺不夠全面,如果不看安裝程序提供的幫助文檔,網上查到的很多中文文章,還真讓人看的一知半解。知其然,不知其所以然,所以本人就乾脆看着幫助文檔來細細研究。先給個下載地址:http://www.microsoft.com/downloads/details.aspx?FamilyId=7B9BA1A7-DD6D-4144-8AC6-DF88223AEE19&displaylang=en
下載後會有一個CAB_CS的安裝文件,安裝即可。
按照微軟官方的說法,Composite UI Application Block (CAB)使用了目前商業客戶端應用程序常用的設計模式來構建了一個靈活的基礎框架。基於這個框架可以很容易的幫助你編寫運行在microsoft .net平臺上的具有複雜用戶交互界面的Windows Form 應用程序。那麼他有哪些優點呢?
1:允許構建由各個具有協作關係的獨立模塊組合成的複雜應用。
2:分離關注點,能將各個模塊的開發的關注點和Shell的開發分離開來。
3:提供了一個能支持高質量的桌面應用開發的框架
4:提高了生產力和節約了開發時間,進一步鞏固了架構師和開發人員的勞動成果。
這些特點如何體現出來呢?我後面的文章將和大家一同來分析。
應用程序架構元素
CAB. Composite UI Application Block的縮寫
Module. 應用程序的組成部件,其中包含SmartParts,支持Service,業務邏輯和配置信息等
ObjectBuilder.通過策略和配置信息自動創建對象實例的對象構造器。
Shell. 承載了用戶接口元素,SmartPart,服務的外殼宿主程序。
Visualizer. CAB中提供的,可以查看應用程序中的WorkItem的動態分級視圖的工具。
外殼元素
shell application. 承載了用戶接口元素,SmartPart,服務的外殼宿主程序。
SmartPart. 一個展現數據的視圖,比如控件,Windows 窗體或是一個嚮導頁。
SmartPartInfo. 存放SmartPart的相關信息的類,以便被workspace所使用,比如可以在Smartpartinfo中設置SmartPart的顯示標題。
UIElement. 一個以Shell作爲宿主的控件,該控件能被多個Module所共享,這樣的控件有:toolbar button , menuitem , status panel等
UIElement adapter. 管理特殊類型的UIElement的顯示的類
Workspace. 封裝了控件和SmartParts的某種可視化的佈局的組件,比如以Tab方式顯示頁面。
相關模式
Blackboard. 通過提供一個共享信息的地方,使其他組件能設置或獲取這個地方的信息,已達到信息共享的模式。
Builder/Inversion of Control/Dependency Injection. 該模式通過組件之間的依賴關係進行運行時的注入,來達到組件重用和鬆散耦合的目的。
Event Broker. 允許鬆散耦合的組件通過發佈訂閱的方式進行通訊的模式。
Memento.持久化一個對象的內部狀態狀態,並在需要的時候可以在後期對狀態進行恢復的模式。
Model-View-Controller (MVC). 該模式將領域模型,視圖和基於用戶輸入產生的行爲(控制器)分成3個不同的組成部分。視圖部分提供給用戶進行交互,交互信息通過視圖傳到控制器,控制器更新模型,模型引發事件,從而更新視圖。關係圖如下:
Model-View-Presenter (MVP). 該模式將領域模型,視圖和基於用戶輸入產生的行爲(控制器)分成3個不同的組成部分。視圖部分提供給用戶進行交互,交互信息通過視圖傳到控制器,控制器更新模型,模式觸發事件到控制器,同時,控制器負責更新視圖。關係圖如下:
相關編程模型
Component. 應用程序的可視或非可視組成部件,比如SmartParts, services, 和控件.
Container. 包含了組件或服務的類。
event broker. 支持鬆散耦合的發佈訂閱事件機制的系統。
State. 存在於WorkItem中,以鍵-值的字典的方式來存放共享信息。
Service.以鬆散耦合的方式爲其他的組件提供功能的組件。比如:ModuleLoaderService
WorkItem. 運行時的組件和服務的容器,該容器能協作其中封裝的用例代碼的執行。一般WorkItem和用例對應。
相關角色
infrastructure developer. 負責進行應用程序的基礎服務的開發的開發人員。
module developer. 負責進行應用程序的業務組件的開發的開發人員。
shell developer. 負責建立應用程序外殼的開發人員。
SmartPart developer. 負責開發應用程序的SmartParts的開發人員。
CAB提供了一個非常靈活的編程框架,利用這一框架,可以很好的將一個應用分離成不同的模塊進行開發。
我們來看看一個基於CAB的典型應用都有哪幾部分組成:
首先一個CAB應用需要通過繼承自FormShellApplication的應用程序類來進行啓動。FormShellApplication需要傳入兩個類型參數,繼承自WorkItem的類,和繼承自Form的類(應用程序主界面FormShell)。主界面上可以放置供所有界面視圖使用的公共的UI Element (如:Toolbar)。和顯示用戶界面的WorkSpace。WorkItem是封裝了用例實現的容器,容器中的對象可以共享信息。WorkItem也可以包含下級WorkItem.
由於CAB的優點之一是能夠很好的支持模塊化開發,業務開發人員可以專注於某一方面業務模塊的開發,如:倉庫管理系統中,入庫和出庫就是同一個系統中的兩個業務點,在CAB的支持下,完全可以將這兩個業務點交由不同的開發人員進行開發,只要按照同樣的既定的規範開發(界面規範,接口規範等),就能很好地進行集成。CAB中通過Module很好的實現了這一點。
一般我們將module實現於dll文件中,每個Dll文件可能包含系統某一方面的功能,當我們在獨立開發好各個Module之後,我們可以利用CAB有選擇的加載這些功能模塊,從而支持系統運行。要實現Module被加載很簡單,只需要在ProfileCatalog.xml中將需要被加載的module配置進去就可以了。當然前提是被加載的模塊需要符合CAB的Module設計的標準。如圖中所示,這個dll中需要有一個繼承自ModuleInit的類,Module被加載的時候,該類的Load方法將被調用,所以大家也可以在繼承類中通過重載Load方法來擴展其加載時的行爲。
一般情況下,在獨立的模塊中,我們還需要實現相應的繼承WorkItem的類來實現其業務用例的封裝,這個WorkItem我們需要將其添加到RootWorkItem的WorkItems集合中,以便和其建立聯繫。
在WorkItem中可以使用MVP的模式來實現我們的系統。上圖中的View是在主窗體的WorkSpace中顯示的和用戶進行交互的界面,Presenter則是響應界面操作,處理業務邏輯的地方,Model則是我們的數據。
雖然我們的系統可以模塊化的獨立開發,各個模塊之間實現了鬆耦合,但是系統運行時,CAB還是需要通過某種方式將各個模塊糅合在一起,以便形成一個有機的整體。首先CAB是一個IOC的容器,它可以在運行時根據需要實例化各種對象,並將其注入到對其有需要的對象中,達到對象的組裝,然後可以通過發佈訂閱事件系統及共享State實現了對象間的通訊。
CAB涉及的Dll有:
常用的命名空間如下:
附兩張CAB中命名空間Microsoft.Practices.CompositeUI和Microsoft.Practices.CompositeUI.Winforms涉及的類和接口:
個人認爲,CAB是的不錯的WinForm應用框架,目前主要還是體現在對界面層和業務邏輯層的支持上。如果配合其他的技術框架如Nhibernate對數據庫層進行支持,將會更好。
現在我們來看看基於CAB的應用程序中非常重要的一個類。這個類可以認爲是一個CAB應用的啓動點。他就是FormShellApplication。
FormShellApplication的繼承關係如下:
該類需要傳入兩個類型參數,一個是繼承自WorkItem的類(如果不需要通過重載WorkItem的OnRunStarted方法來實現更多處理,這裏可以直接使用WorkItem),一個是繼承自Form的窗體。
public class Program:FormShellApplication<MyWorkItem,ShellForm>
通常我們在Main方法中調用其Run方法,執行Run方法會初始化許多應用程序信息。可以通過override來重寫或增加FormShellApplication的方法處理。
FormShellApplication的初始化包括(可以通過子類重載FormShellApplication的相關方法來判斷其執行順序)以下步驟:
1. RegisterUnhandledExceptionHandler |
2. 創建 Build strategies |
3. 創建頂級 WorkItem |
4. 創建和初始化 Visualizer |
5. 添加 services |
6.創建Shell |
CAB提供的標準服務如下,開發人員可以在此基礎上進行擴展:
ü SimpleWorkItemActivationService
ü FileCatalogModuleEnumerator
ü WindowsPrincipalAuthenticationService
ü ModuleLoaderService
ü DataProtectionCryptographyService
ü TraceSourceCatalogService
ü CommandAdapterMapService
ü WorkItemExtensionService
ü WorkItemTypeCatalogService
ü ControlActivationService
執行了FormShellApplication的子類的Run方法,一個CAB應用程序就算是啓動了。隨後就是根據自己的需要來執行WorkItem了。
通過前面的介紹我們可以知道在靜態Main方法中執行繼承自FormShellApplication的對象實例可以進行很多框架的初始化工作,如加載模塊,加載服務等。從FormShellApplication的類型定義中:
public abstract class FormShellApplication<TWorkItem,TShell> : WindowsFormsApplication<TWorkItem,TShell> where TWorkItem : WorkItem where TShell : Form
可以看到,需要兩個類型參數,一個是WorkItem,一個是Form,FormShellApplication在進行初始化工作的時候會對這兩個類型進行實例化。並且會將Form類型的實例 Show出來。這裏的Form類型的實例即是我們應用程序的主界面。
主界面將是用戶與系統的主要交互區域。他將做爲一個容器,承載其他的業務界面。
CAB中提供了WorkSpace組件,他作爲用戶控件和SmartPart控件的顯示容器,可以以各種各樣的統一的顯示方式呈現業務界面。也就是說WorkSpace可以以不同的風格呈現其中的用戶控件。WorkSpace支持顯示,隱藏,激活和關閉其中的用戶控件。當然,CAB目前提供了幾種默認的顯示風格,接下來我們將一個一個介紹,如果開發人員覺得這些顯示風格還不夠用,當然也可以自己進行擴展。
所有類型的WorkSpace都是實現了接口IWorkSpace的。
目前CAB提供的WorkSpace有:
WindowWorkspace
MdiWorkspace
TabWorkspace
DeckWorkspace
ZoneWorkspace
下面就來說說每種WorkSpace的特點:
1, WindowWorkSpace
該WorkSpace能將你需要在其中顯示的用戶控件在一個WinForm中顯示出來,我們可以通過和該WorkSpace對應的WindowSmartPartInfo來設置用戶控件的顯示屬性,如標題信息,是否是模式窗口等。
2, MdiWorkspace
該WorkSpace是在WindowWorkSpace的基礎上發展而來的,他同樣將一個用戶控件在單獨的Form中進行顯示,並且,他還將以MDI的形式顯示和管理其子窗體。對應用戶控件的顯示信息的設置是通過設置smartPartInfo,然後作爲參數傳入WorkSpace的Show方法。
3, TabWorkspace
該WorkSpace能將你需要在其中顯示的用戶控件以Tab頁的形式顯示出來,我們可以通過和該WorkSpace對應的TabSmartPartInfo來設置用戶控件的顯示屬性,如標題信息。
4, DeckWorkspace
該WorkSpace將以類似於重疊的卡片的形式來顯示用戶控件,當前激活的界面將在卡片的最上方。卡片的數序是由Workspace進行管理。沒有和該WorkSpace對應的SmartPartinfo.
5, ZoneWorkspace
該WorkSpace將以平鋪的方式顯示用戶控件,比如類似OutLook的界面,可以將一個界面劃分成多個Zone,每個Zone都是作爲呈現用戶控件的一個容器。同樣的,我們可以通過設置ZoneSmartPartInfo來設置用戶控件在WorkSpace中的顯示屬性。
首先看看WorkItem都包含哪些元素?
從WorkItem的屬性列表中我們可以看出,WorkItem中支持命令和事件,同時WorkItem可以嵌套,通過Parent進行關聯,通過RootWorkItem可以獲取頂層WorkItem,開發人員可以利用這一特性來組織自己業務用例和劃分業務用例的粒度。WorkItem中使用State來共享信息,在同一個WorkItem容器中的對象可以共享訪問這個信息。 WorkItem容器中的對象對其中的Service都可以訪問。
WorkItem通過調用Run方法進行啓動,調用這個方法的時候會調用他的OnRunStarted方法,一般我們自定義了一個WorkItem,如果有需要可以重載其OnRunStarted方法來自定義其啓動邏輯。Run方法調用後會觸發RunStarted事件。
一般我們會藉助WorkItem提供的特性,採用MVC的模式進行業務用例的封裝。使用SmartPart作爲用戶交互的UI顯示部分(View),創建一個控制類來進行業務邏輯的封裝(Controller),然後將業務數據存放於內存實體中(Model)。用戶界面和內存實體採用綁定的方式關聯起來。
MVC模式的應用,我們來看看他的初始化和用戶交互過程中的操作是如何進行的?
初始化:
1,應用系統加載WorkItem,WorkItem將用戶界面在WorkSpace中進行顯示
2,用戶界面加載,調用控制邏輯進行初始數據的處理和獲取
3,控制邏輯獲取初始數據
4,控制邏輯將數據存放於內存實體中
5,控制邏輯將數據與用戶界面進行綁定,界面會自動根據綁定的數據源進行初始化顯示
用戶交互:
1,用戶操作用戶界面,調用相應控制邏輯
2,控制邏輯進行業務處理,進行相關服務或數據庫訪問
3,控制邏輯修改內存實體中的數據
4,由於數據與界面綁定,數據的變化直接反應到界面顯示。
Composite UI Application Block學習筆記之Smart Part
一、簡單概念介紹
CAB提供一個開發環境能很好的隱藏複雜度和提高生產力,通過高度抽象和關注點的分離,開發人員能夠關注於業務邏輯提高基礎框架代碼的複用。Smart Part是整個CAB體系中重要的一部分,它可以將界面獨立於業務邏輯,讓界面和業務邏輯鬆散的耦合起來。Smart Part的應用中有幾個重要概念:
WorkSpace:作爲一個容器,它可以統一的添加和顯示視圖。CAB中提供了一組控件作爲視圖的容器,包括DeckWorkSpace,MDIWorkSpace,TabWorkSpace,WindowWorkSpace,ZoneWorkSpace。它們的作用有點類似普通Windows 控件Panel,MDI窗口,TAB控件,Window窗體。在程序中根據名稱可以通過WorkItem的WorkSpace集合索引到它們。
Smart Part: 也可以被稱作View,實際上是一個個自定義的控件。
其他像WorkItem, State之類的概念我在前兩次的學習筆記中曾經介紹過了,這裏就不再羅嗦了。
我們利用CAB中WorkSpace和Smart Part到底可以做些什麼呢?WorkSpace可以一致的顯示多個控件,Shell 開發人員創建定製的 workspaces 以提供控件周圍相似的框架和修飾,共享的佈局和定位,眩目的界面切換。下面我們還是通過一個實例來逐步理解CAB之Smart Part應用給我們帶來的好處,特別是在多個數據來源,將多個界面塊組合成一個統一美觀的整體時的應用方便性。
二、實例研究
1.應用場景
我相信研究過CAB的朋友肯定知道微軟提及的一個應用案例,Dell的客服桌面應用。該應用就是爲了提高克服人員的辦公效率,將在提供客戶服務過程中需要從多個軟件系統獲取的信息,統一的集成到一個界面上來。也許大家會爲該應用卓越的表現力,而感到親切、人性化,其實類似這樣的應用我們通過CAB基礎件的應用,也可以達到類似的效果,而不需要在界面化太多的精力去處理業務和界面之間的交互。爲了能夠說明問題,我在學習過程中也做了一個簡單的例子。
大家可能都開發過網站或者用過Share point portal,那大家肯定都應該知道Web Part這個概念,在CAB中類似的有了Smart Part的概念。Web Part能將一個個的信息塊集成到一個統一的Portal,Smart Part也能將不同的信息塊集成到一個界面。我們不妨假設這樣一個應用場景:
假設您是某百貨店的店長,希望每天能看到店裏的銷售業績,能看到自己每天的郵件,能看到自己喜歡的Blog上的資源,能有軟件提示自己每天的行程安排,最重要的是這些信息需要在一個統一的界面上顯示出來。面對這樣的需求,CAB來開發界面大有用武之地,如果採用SOA的架構,更能使遺產系統的價值利用得更好。
2.需求分析
具體來說該軟件有以下需求:
a.銷售業績的信息從店面現有的進銷存系統中獲得。
b.Blog信息通過RSS獲得
c.每天的日程安排情況從祕書給自己設定的OA系統中獲得。
d.電子郵件通過集團統一的電子郵件系統中獲得,該郵件系統支持Web Service。
e.軟件界面簡單統一,不能有過多的界面切換,最好能將所有概要信息顯示在一個界面之上。
f.軟件開發週期要短,儘量利用現有系統的數據和邏輯。
g.界面可能會擴展,以後可能需要集成更多的系統。
面對這些需求,我們不難得出結論:用CAB基礎件開發界面,用Web Service集成遺產系統信息都是不錯的選擇。
3.開始建立應用
由於本例我們主要是爲了學習CAB,至於Web Service的應用不做闡述。爲了模擬類似的效果,和SOA系統開發過程中共享契約的原則,我們通過數據集來代表契約(XSD文件),用實際的XML文件代表Web Service的返回結果。
第一步:建立解決方案
a.啓動VS2005,新建windows application,命名爲TestSmartPart在項目中引用以下組件:
- Microsoft.Practices.CompositeUI;
- Microsoft.Practices.CompositeUI.WinForms;
- Microsoft.Practices.ObjectBuilder
第二步:繪製主窗口
a.將系統默認產生的Form1窗體,命名爲TestSmartPartForm。
b.通過菜單-->工具-->自定義工具箱,選擇瀏覽Microsoft.Practices.CompositeUI.WinForms.dll,這是工具箱中能出現DeckWorkSpace,MDIWorkSpace等控件。
c.打開TestSmartPartForm的設計視圖,調整窗體的高度和寬度,繪製5個DeckWorkSpace控件,分別命名爲deckWS_Calendar,deckWS_Blogs,deckWS_Plan,deckWS_Task,deckWS_MainEmail。最終的界面效果如下圖:
第三步:定義數據實體(或者定義服務契約)
a.新建DataSources文件夾。
b.在DataSources文件夾中添加myBlogs,myEmail,myTasks,myPlans四個數據集。具體結構在文中不作描述,大家可以參考文後的源代碼。
c.根據數據集的結構,建立數據源。這裏我們用Xml文件來代替數據庫中讀取的數據,分別添加myBlogs.xml,myEmail.xml,myTasks.xml,myPlans.xml。數據的內容我在此略過。將各個Xml文件內容錄入完成後,拷貝到運行目錄。我不知道爲什麼設置文件的Copy To OutPut Dierctory屬性爲always,VS.Net編譯項目的時候無法複製到輸出目錄,難道該屬性是在建立安裝程序才起作用?後來我發現是生成的時候連同DataSource文件夾,一起輸出到了Bin目錄,因此讀取的時候也需要加上DataSource目錄。
第四步:建立視圖
a.建立BlogView、DailyPlan、DailyTask、Emails四個文件夾,這樣做的目的只是爲了讓項目的結構更加清晰,同時以後要是對這些視圖進行擴展,也可以把子視圖都放到對應的文件夾裏。
b.在項目根目錄下添加UserControl,命名爲TitlePart.cs。給該用戶控件加上一個lable控件,並且加入以下代碼:
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using Microsoft.Practices.CompositeUI.SmartParts;
namespace TestSmartPart
{
[SmartPart]
public partial class TitlePart : UserControl
{
public TitlePart()
{
InitializeComponent();
}
/**//// <summary>
/// Text that will show in the title label.
/// </summary>
public string Title
{
get
{
return lblTitle.Text;
}
set
{
lblTitle.Text = value;
}
}
/**//// <summary>
/// Tooltip for the smartpart.
/// </summary>
public string Description
{
get
{
return toolTip.GetToolTip(lblTitle);
}
set
{
toolTip.SetToolTip(lblTitle, value);
}
}
}
}
c.建立BlogView視圖。在文件夾BlogView新建UserControl,命名爲myBlogView.cs。將該類從TitlePart繼承,將標題設置爲“我的博客".加入Grid控件和數據集myBlogs進行綁定。最終效果如下圖:
d.建立dailyPlanView視圖。在文件夾DailyPlan中新建用戶控件,命名爲myPlan.cs。將該類從TitlePart繼承,將標題設置爲“我的日程"。加入Grid控件和數據myPlans進行綁定。
e.建立myTaskView視圖。在文件夾DailyTask中新建一個UserControl,命名爲myTask.cs,將該類從TitlePart繼承,將標題設置爲“銷售報表"。進入myTask.cs的設計時加入控件reportView1,同時根據myTask數據集建立柱狀圖。最終界面如下圖:
f.建立EmailView視圖。爲了表現WorkSpace能夠層層顯示子視圖,我們在EmailView視圖上,添加了兩個DeckworkSpace用來顯示郵件的列表視圖和詳細信息視圖。EmailView本身又是通過上一級WorkSpace顯示的。這裏略去郵件列表視圖和郵件詳細信息視圖的建立過程,請參前面視圖建立過程和源代碼。
到此我們基本上完成各個視圖的建立,大家不難發現,他們之間是相對獨立的,和WorkSpace無關的。
第五步:編寫WorkItem和Controller,連接所有視圖
a.建立應用入口類。新建SmartPartApplication.cs,將類代碼修改成以下形式:
using System.Collections.Generic;
using System.Windows.Forms;
using Microsoft.Practices.CompositeUI;
using Microsoft.Practices.CompositeUI.WinForms;
using System.Data;
namespace TestSmartPart
{
//注意這句程序,它能將窗體和特定的WorkItem關聯。沒有沒有特定的WorkItem,採用默認的“WorkItem”代替“SmartRootWorkItem”。
class SmartPartApplication : FormShellApplication<SmartRootWorkItem, TestSmartPartForm>
{
/**//// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
public static void Main()
{
new SmartPartApplication().Run();
}
protected override void BeforeShellCreated()
{
base.BeforeShellCreated();
}
b.建立根級別的WorkItem。在本例中WorkItem的主要作用是提供顯示試圖的方法,將業務實體數據填充到數據集,並且讓數據集和控件綁定。
以顯示BlogView爲例,我們來說明WorkItem是如何將BlogView展示到特定的WorkSpace的。首先我們來看以下代碼:
using System.Collections.Generic;
using System.Text;
using Microsoft.Practices.CompositeUI;
using Microsoft.Practices.CompositeUI.SmartParts;
using Microsoft.Practices.ObjectBuilder;
using System.Data;
namespace TestSmartPart
{
public class SmartRootWorkItem : WorkItem
{
private TestSmartPart.BlogView.myBlogView blogView;
public override void Run()
{
ShowBlogView();
}
private void ShowBlogView()
{
this.State["BlogDataSet"] = new DataSet();
((DataSet)this.State["blogDataSet"]).ReadXml("myBlogs.xml");
IWorkspace blogWorkspace = this.Workspaces["deckWS_Blogs"];
blogView = this.Items.AddNew<TestSmartPart.BlogView.myBlogView>("BlogView");
blogWorkspace.Show(blogView);
}
}
}
系統通過入口程序會自動調用SmartRootWorkItem的Run方法,然後調用ShowBlogView方法來顯示Blog視圖。我們需要重點關注的是ShowBlogView本身。在顯示視圖之前我們需要爲視圖中用到的數據,創建實例並且將其載入WorkItem的State列表,以便在視圖和Controller中共享使用。如代碼:
((DataSet)this.State["blogDataSet"]).ReadXml("myBlogs.xml");
最後我們需要將視圖,在住窗體的deckWS_Blogs控件中顯示。在WorkItem中我們直接可以通過this.Workspace[]來索引住窗體上的Workspace,CAB已經自動將在設計時添加的Workspace控件添加到了Workspaces列表。索引導特定的Workspace後,我們需要將要顯示的試圖添加到WorkItem的Items集合,最後通過Workspace.Show(view)來顯示視圖。代碼如下:
blogView = this.Items.AddNew<TestSmartPart.BlogView.myBlogView>("BlogView");
blogWorkspace.Show(blogView);
其他視圖的添加方法類似,我就不再做說明。
c.正對根級別的WorkItem,建立對應的Controller。新建RootController.cs,將RootController類從Controller繼承,加入以下代碼,將其與WorkItem關聯。
[ServiceDependency(Type = typeof(WorkItem))]
public SmartRootWorkItem RootWorkItem
{
set
{
rootWorkItem = value;
}
}
同時爲了將業務實體和WorkItem、View結合起來,我們將數據集通過State列表共享。如以下代碼:
public DataSet BlogDataSet
{
set
{
if (value != null && State != null)
{
State["BlogDataSet"] = value;
}
}
get
{
return (DataSet)State["BlogDataSet"];
}
}
RootController類中當然還共享了其他如DailyPlan、DailyTask等業務數據,由於篇幅不再列出,在源代碼中可以查看。
第六步:修改視圖代碼,在視圖中顯示數據。
我們還是以BlogView爲例來說明,視圖是如何將數據顯示出來的,其他視圖都相似,請參考源代碼。在視圖中主要是通過私有變量和加有[State]修飾符的屬性和業務數據、Controller相關聯的。代碼如下:
[CreateNew]
public RootController Controller
{
set
{
controller = value;
}
}
private DataSet blogDataSet = null;
[State]
public DataSet BlogDataSet
{
set
{
blogDataSet = value;
}
}
第七步:特殊處理,視圖的嵌套。
EmailView視圖和其他視圖有些不一樣,EmailView視圖有DeckWorkspace,在DeckWorkspace中還必須顯示兩個子視圖。這樣就使數據的共享,WorkItem的訪問存在少許差異。我們不妨首先來看SamrtRootWorkItem中顯示EmailView的方法:
{
IWorkspace workspace = this.Workspaces["deckWS_MainEmail"];
emailView = this.Items.AddNew<TestSmartPart.Emails.EmailView>("EmailView");
workspace.Show(emailView);
if (emailWorkItem == null)
{
emailWorkItem = this.Items.AddNew<TestSmartPart.Emails.EmailWorkItem>("EmailWorkItem");
}
emailWorkItem.State["emailDataSet"] = new DataSet();
((DataSet)emailWorkItem.State["emailDataSet"]).ReadXml("myEmails.xml");
emailWorkItem.Run();
}
我們發現TestSmartPart.Emails.EmailWorkItem被加入SamrtRootWorkItem的Items集合,deckWS_MainEmail這個Workspace也被加入SamrtRootWorkItem的Items集合。因此訪問這些Workspace時,必須通過WorkItem.Parent.Workspaces[ ]來訪問。代碼如下:
{
private EmailDetailView emailDetailView;
private EmailTitleView emailTitleView;
public override void Run()
{
emailDetailView = this.Items.AddNew<EmailDetailView>("EmailDetailView");
emailTitleView = this.Items.AddNew<EmailTitleView>("EmailTitleView");
IWorkspace titleWorkspace = this.Parent.Workspaces["deckWS_EmailTitle"];
IWorkspace detailWorkspace = this.Parent.Workspaces["deckWS_EmailDetail"];
titleWorkspace.Show(emailTitleView);
detailWorkspace.Show(emailDetailView);
}
}
第八步:運行程序
經過一些修改後,我們可以運行我們的例程,大家看看下面這個界面是不是像一個Portal啊?