Composite UI Application Block学习笔记之Event Broker
Composite UI Application Block著重于將應用邏輯和界面分開,讓應用系統具備更清晰的結構,更強的擴展性、可移植性。在曹嚴明先生的講座中,提及到了關于應用CAB開發的幾個指導性原則:
- 將 views (SmartPart)設計為獨立于 controllers 的單元
- 共享模塊狀態
- 共享基礎服務
- 封裝用例 - 重用
- 降低模塊間的依賴性
- 盡量使用 events, services, and interfaces
???? 我在學習的過程中也理解到以上原則的重要性和指導性,在我學習模塊狀態和Event Broker的過程中,也將上述部分原則做了特意的應用。那么我們還是通過一個實例來學習Event Broker和這些原則。
一、文中有關術語
??? 下面這些術語是CAB中常用到的,以下的解釋僅是我個人的理解,不敢保證完全準確,園子里的朋友請指教。
??? Event Broker:事件代理,通過事件源和訂閱事件源來達成對象之間的協作。
??? Event Publisher: 事件發布者,在CAB里是一個用屬性EventPublication修飾的事件對象,提供特定的URL給Event Subscriber訂閱。
??? Event Subscriber: 事件訂閱者,在CAB里是一個用屬性EventSubscription修飾的方法,根據修飾提供的URL自動尋找事件發布者。Publisher和Subscriber之間由主題(由URL決定),消息(特定的 EventArgs),事件域(來確定是全局事件還是局部事件)來達成一致。其實這也是觀察者模式的具體實現。
??? WorkItem:代表一個用例,也可以看成是某個業務完成的過程,它包含在WorkSpace中,服務于Service Agents(服務代理),并且加載其狀態。創建其他組件或者視圖,CAB來創建controller.組件共享WorkItem的狀態,并且可以通過狀態來控制用例的生命周期。
??? WorkItem State:狀態,實際上是把業務對象或者業務對象的屬性,通過WorkItem State共享出來,方便其他業務對象或者視圖訪問。
二、體驗Event Broker應用
??? 講了這么多有關Event Broker的理論和概念了,我們還是通過一個簡單的例子來體驗Event Broker這種實現模式的優越性吧。
1.應用場景
???? 平時我們在開發過程中碰到最多的例子大概就是,一個業務對象數據集要通過dataGrip,ListBox甚至Chart控件等將其表現出來了。今天,我在學習筆記里也以這個例子來闡述Event Broker,在開發中帶來的好處。
??? 場景是這樣的:某人事信息管理軟件要求輸入人員的性別和姓名,并且能將輸入的人員在通過表格和列表框的形式表現出來,同時錄入人員的男女比例要能適時的通過餅圖顯示。
2.分析場景,確定開發模式
a.需求中涉及到的唯一業務對象是人員,具有性別和姓名兩個屬性。為了簡單起見我們可以建立數據集來代替該對象。
b.需求要求能輸入姓名、性別,我們可以用文本框和下拉框來完成信息采集。
c.需求要求人員信息,通過表格,ListBox和餅圖來顯示,我們可以在VS2005中用DataGrid、ListBox、ReportView來實現此項需求。
d.由于業務對象單一,而信息表現卻又多個,適合用觀察者模式進行開發。我們便采用CAB中的Event Broker作為重要的實現手段。
3.建立應用程序
第一步:新建項目
???? 啟動VS2005,新建Windows Application,添加以下引用:
Microsoft.Practices.CompositeUI
Microsoft.Practices.CompositeUI.WinForms
Microsoft.Practices.ObjectBuiler
Microsoft.Practices.CompositeUI.Utility
Microsoft.Practices.CompositeUI.WinForms
第二步:建立數據集
??? 右擊項目文件夾,添加新項,選擇數據集,建立用戶信息數據集(沒有通過代碼創建,主要是為了設計報表方便)。為數據集添加DataTable1的表,為DataTable1添加列Sex和Name。
第三步:繪制界面
???? 在VS2005默認生成的Form1上建立餅圖、DataGrid、ListBox和相關相關控件,具體操作我在此略過,最終效果如下圖:
第四步:修改入口程序
??? 為了讓程序能使用CAB,我們必須修改程序的入口類Program.cs。最終修改結果如下:
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Data;
using Microsoft.Practices.CompositeUI;
using Microsoft.Practices.CompositeUI.WinForms;
namespace TestReport
{
class Program : FormShellApplication<WorkItem, Form1>
{
/** <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
new Program().Run();
}
protected override void BeforeShellCreated()
{
base.BeforeShellCreated();
//共享狀態,通過"dataset"關鍵字訪問
? RootWorkItem.State["dataset"] = new DataSet1();
}
}
}
?? 需要注意的是:為了能使用WorkItem的State,在Shell創建之前必須給共享的狀態賦初值,否則在訪問該狀態時將出現狀態沒有創建實例的運行時錯誤。本例中就是加入以下代碼:
protected override void BeforeShellCreated()
{
base.BeforeShellCreated();
? RootWorkItem.State["dataset"] = new DataSet1();
}
第五步:建立controller
建立controller負責用戶信息添加,建立事件源。添加類文件,命名為Form1Controller,將該類從controller繼承。如下代碼所示:
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Practices.CompositeUI;
using Microsoft.Practices.CompositeUI.EventBroker;
using Microsoft.Practices.CompositeUI.Utility;
using System.Data;
namespace TestReport
{
public class Form1Controller: Controller
{
? }
}
在controller中公布一個事件發布者,通過"topic://TestReport/DataRowAdded"來標識Publisher,默認的事件域為全局。也可以通過PublicationScope枚舉來設置事件的作用域。事件作用域有以下三種:
PublicationScope.WorkItem :僅作用于引發當前發布的WorkItem實例
PublicationScope.Global:作用于引發當前發布的WorkItem所有實例
PublicationScope.Descendants:僅作用于引發當前發布的WorkItem實例,以及該WorkItem的任何級別的子WorkItem實例。
本例通過以下代碼發布事件:
[EventPublication("topic://TestReport/DataRowAdded")]
public event EventHandler<DictionaryEventArgs> DataRowAdded;
controller中主要來實現業務邏輯,于是我們需要添加一個方法AddNewRow(int sex, string name),用來實現人員信息的添加,代碼如下:
private DataSet1 ctldataset;
//controller的AddNewRow方法,引發事件DataRowAdded
public void AddNewRow(int sex, string name)
{
if (DataRowAdded != null)
{
? DataRow myRow = ctldataset.DataTable1.NewRow();
? myRow[0] = sex;
? myRow[1] = name;
? ctldataset.DataTable1.Rows.Add(myRow);
? ctldataset.AcceptChanges();
? DictionaryEventArgs args = new DictionaryEventArgs();
? args.Data["dataRow"] = myRow;
? DataRowAdded(this, args);
? State.RaiseStateChanged("dataset", myRow);
}
}
?? 大家請注意下面代碼,其實是定義了一個DictionaryEventArgs參數,并且將當前添加的行對象作為該參數的值。當DataTable1中行添加后,我們引發事件DataRowAdded(this, args)。? 此時,事件源被觸發了,訂閱者就可以接收到該事件廣播了。
DictionaryEventArgs args = new DictionaryEventArgs();
args.Data["dataRow"] = myRow;
DataRowAdded(this, args);
?? 到此,我們已經完成了事件源的創建和發布,為了達到演示的效果,我們還需要實現共享WorkItem State來廣播事件。如以下代碼:
[State("dataset")]
public DataSet1 CtlDataSet?
{
set
{
? ctldataset = value;
}
}
public new State State
{
get { return base.State; }
}
??? 我們注意到[State("dataset")]這行代碼,它是用來表示WorkItem的屬性CtlDataSet,將通過[State("dataset")]共享出去,同時當CtlDataSet改變時,通過代碼State.RaiseStateChanged("dataset", myRow),來引發狀態改變事件,其他地方就可以得到該事件的委托。
第六步:整合界面和controller
??? 我們回到Form1.cs編輯代碼。為了讓界面和controller和界面結合,我們將controller作為界面對象的一個屬性,用以下代碼實現:
//定義該窗體相關的Controller
private Form1Controller controller;
//將該窗體相關的Controller標記為自動創建實例
[CreateNew]
public Form1Controller Controller
{
set { controller = value; }
}
?? 為添加按鈕加入代碼,實現添加一個人員信息:
private void btn_AddToTable_Click(object sender, EventArgs e)
{
if((this.textBox1.Text.Trim().Length >0))
{
this.controller.AddNewRow(this.cmbSex.SelectedIndex, this.textBox1.Text.Trim());
}
}
?? 還有為了讓Grid和report view能夠同步顯示人員信息,我們需要訂閱由topic://TestReport/DataRowAdded標示的事件:
[EventSubscription("topic://TestReport/DataRowAdded")]
public void OnCustomerAdded(object sender, DictionaryEventArgs e)
{
this.dataGridView1.DataSource = ((DataSet1)this.controller.State["dataset"]).DataTable1.DefaultView;
this.DataTable1BindingSource.DataSource = ((DataSet1)this.controller.State["dataset"]).DataTable1.DefaultView;
this.reportViewer1.RefreshReport();
}
?? 這樣每添加一個人員,Grid和Reoport View就能適時更新自身表現了,這就是Event Broker的實現方式,簡單并且簡潔。前面我們還提到了通過共享狀態來實現視圖和業務對象的關聯,在本例中也提供實現。
首先,在FormLoad事件中訂閱StateChanged事件:
private void Form1_Load(object sender, EventArgs e)
{
this.controller.State.StateChanged += new EventHandler<StateChangedEventArgs>(State_Changed);
}
然后,通過代碼更新List狀態:
void State_Changed(object sender, StateChangedEventArgs e)
{
this.listBox1.DataSource = ((DataSet1)this.controller.State["dataset"]).DataTable1.DefaultView;
this.listBox1.DisplayMember = "Name";
this.listBox1.ValueMember = "Name";
}
好了,到此我們的例程已經大功告成,最終的運行效果如下圖:
本文相關代碼通過此連接下載:/Files/hyphappy/TestReport.rar
轉載于:https://www.cnblogs.com/HeroBeast/archive/2009/01/15/1376321.html
總結
以上是生活随笔為你收集整理的Composite UI Application Block学习笔记之Event Broker的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 东软刘积仁:软件已从高科技领域变成大众消
- 下一篇: 1.2 User Interface