记得早年在乡间
对外的通信往来主要依靠一种特殊职业的人
信客
外出谋生的人多了
少不了要带几封平安家信
捎一点衣物食品的
那就用得着信客了
信客要有一点文化
知道各大码头的情形
还要一副强健的筋骨
背得动重重的行李
信客沉重的脚步
是乡村和城市的纽带
余秋雨《文化苦旅·信客》
■ 一个馒头引发的血案 回发与事件
基于Web的分布式系统中用户往往是通过提交表单浏览器产生相应的HTTP POST请求来完成交互过程这个过程称为回发(PostBack)在同一个网页中常会有许多HTML标签可能引起回发申请交于服务器处理
控件对应着客户端的HTML标签有着自己的状态和行为用户操作引起每一次回发会调用页面中一个或多个控件行为修改其状态也就是说杯中的粉圆(《随想十》中对控件的比喻)之间是有关联的用户拨动其中一个可能引起其它粉圆震动拓展开来当用户操作或系统内部引发状态改变时类需要发送一个消息给关联类让关联类做相应的状态调整框架中这个消息被称为事件(event)发接消息的类被称为事件源(event source)关联类被称为事件接收者(event sink)回发的处理过程实质上是事件源调用事件接收者的行为函数称为回调(callback)
我们不希望在编译时就确定回调的对象否则这种强耦合关系就意味着每次使用时需要拎一串关联粉圆放到杯子中相反我们希望到运行时再来确定回调关系在NET框架中这种方式被定义成委托(delegate)我们在《随想七》和《随想八》已经对其有了初步的认识事件基于发布订阅机制每一个产生事件的类都有一个委托成员(发布机制)在系统初始化时接收器或其它类需要将具体的事件处理程序绑定到委托成员(订阅机制)运行时系统自动完成回调
■ 口信 用户操作引发的服务器端事件
终于有妇女来给信客说悄悄话关照他往后带东西几次并一次不要鸡零狗碎的你给他说说那些货色不能在上海存存?我一个女人家来强盗来贼怎麽办……信客沉稳地点点头
用户会对客户端浏览器中的页面元素做出各种操作浏览器可以通过JavaSript之类的脚本语言来捕获这些操作并且做出相应回应但对服务器而言它却常常视而不见要产生服务器端事件就必须在设计期让事件源对应的表单元素引发带有鲜明特征的回发从而让页面能够正确识别并传递给控件以做相应回调完成用户操作到事件的映射过程
ASPNET用接口IPostBackEventHandler做为信客的口信带回远方的消息它包含一个方法RaisePostBackEvent在回传后页面会在控件树中寻找与引发回传HTML元素的UniqueID相匹配的控件并调用该方法下例为依赖于用户点击引发事件的自定义控件范例
// MyControlscs 自定义控件集
using System;
using SystemComponentModel;
using SystemWebUI;
using SystemWebUIWebControls;
namespace essay
{
public class myButton:WebControlIPostBackEventHandler
{
//定义控件属性Text
public virtual string Text
{
get
{
string s =(string)ViewState[Text];
return (s==null)?stringEmpty:s;
}
set {ViewState[Text]=value;}
}
//生成控件对应的HTML代码
protected override void Render(HtmlTextWriter writer)
{
writerWrite(<INPUT TYPE=submit name= + thisUniqueID + Value=+thisText+ />);
}
//定义Click事件委托
public event EventHandler Click;
//把客户端提交映射到自定义的Click事件
void IPostBackEventHandlerRaisePostBackEvent(string eventArgument)
{ OnClick(EventArgsEmpty); }
//实现回调
protected virtual void OnClick(EventArgs e)
{ if(Click!=null)Click(thise); }
}
}