記得早年在鄉間
對外的通信往來主要依靠一種特殊職業的人
信客
外出謀生的人多了
少不了要帶幾封平安家信
捎一點衣物食品的
那就用得著信客了
信客要有一點文化
知道各大碼頭的情形
還要一副強健的筋骨
背得動重重的行李
信客沉重的腳步
是鄉村和城市的紐帶
余秋雨《文化苦旅·信客》
■ 一個饅頭引發的血案
回發與事件
基於Web的分布式系統中
用戶往往是通過提交表單
浏覽器產生相應的HTTP POST請求來完成交互過程
這個過程稱為回發(PostBack)
在同一個網頁中
常會有許多HTML標簽可能引起回發
申請交於服務器處理
控件對應著客戶端的HTML標簽
有著自己的狀態和行為
用戶操作引起每一次回發
會調用頁面中一個或多個控件行為修改其狀態
也就是說
杯中的粉圓(《隨想十》中對控件的比喻)之間是有關聯的
用戶撥動其中一個
可能引起其它粉圓震動
拓展開來
當用戶操作或系統內部引發狀態改變時
類需要發送一個消息給關聯類
讓關聯類做相應的狀態調整
框架中
這個消息被稱為事件(event)
發接消息的類被稱為事件源(event source)
關聯類被稱為事件接收者(event sink)
回發的處理過程
實質上是事件源調用事件接收者的行為函數
稱為回調(callback)
我們不希望在編譯時就確定回調的對象
否則這種強耦合關系就意味著每次使用時需要拎一串關聯粉圓放到杯子中
相反
我們希望到運行時再來確定回調關系
在
NET框架中
這種方式被定義成委托(delegate)
我們在《隨想七》和《隨想八》已經對其有了初步的認識
事件基於發布
訂閱機制
每一個產生事件的類都有一個委托成員(發布機制)
在系統初始化時
接收器或其它類需要將具體的事件處理程序綁定到委托成員(訂閱機制)
運行時
系統自動完成回調
■ 口信
用戶操作引發的服務器端事件
終於有婦女來給信客說悄悄話
關照他
往後帶東西幾次並一次
不要雞零狗碎的
你給他說說
那些貨色不能在上海存存?我一個女人家
來強盜來賊怎麽辦
……信客沉穩地點點頭
用戶會對客戶端浏覽器中的頁面元素做出各種操作
浏覽器可以通過JavaSript之類的腳本語言來捕獲這些操作並且做出相應回應
但對服務器而言
它卻常常視而不見
要產生服務器端事件
就必須在設計期讓事件源對應的表單元素引發帶有鮮明特征的回發
從而讓頁面能夠正確識別
並傳遞給控件以做相應回調
完成用戶操作到事件的映射過程
ASP
NET用接口IPostBackEventHandler做為信客的口信
帶回遠方的消息
它包含一個方法
RaisePostBackEvent
在回傳後
頁面會在控件樹中尋找與引發回傳HTML元素的UniqueID相匹配的控件
並調用該方法
下例為依賴於用戶點擊引發事件的自定義控件范例
// MyControls
cs 自定義控件集
using System;
using System
ComponentModel;
using System
Web
UI;
using System
Web
UI
WebControls;
namespace essay
{
public class myButton:WebControl
IPostBackEventHandler
{
//定義控件屬性Text
public virtual string Text
{
get
{
string s =(string)ViewState[
Text
];
return (s==null)?string
Empty:s;
}
set {ViewState[
Text
]=value;}
}
//生成控件對應的HTML代碼
protected override void Render(HtmlTextWriter writer)
{
writer
Write(
<INPUT TYPE=submit name=
+ this
UniqueID +
Value=
+this
Text+
/>
);
}
//定義Click事件委托
public event EventHandler Click;
//把客戶端提交映射到自定義的Click事件
void IPostBackEventHandler
RaisePostBackEvent(string eventArgument)
{ OnClick(EventArgs
Empty); }
//實現回調
protected virtual void OnClick(EventArgs e)
{ if(Click!=null)Click(this
e); }
}
}
From:http://tw.wingwit.com/Article/program/net/201311/13052.html