IPostBackDataHandler
2008-08-25 10:57
274 查看
IPostBackDataHandler和IPostBackEventHandler对于实现一个WebControl是非常重要的,如果你的 Contro仅仅是readonly的,也就是说不会让客户端进行输入和修改,那么这两个接口就没有用,一旦你要和客户端交互,那么这两个接口是必须掌握的。IPostBackDataHandler可以让你的Control和客户端的输入数据进行交互,比如TextBox,CheckBox,而 IPostBackEventHandler可以让你的Control和客户端的动作行为进行交互,比如Button(click行为)。如果你既希望接收客户端的数据,也希望接收客户端的行为,那么就要同时实现这两个接口了。
在我的上一篇文章《页面的生命周期》里面,我详细介绍了页面生存周期的各个阶段,但是对于PostBack阶段介绍的并不是很多,在本文里面我将详细补充介绍页面生存周期的PostBack 阶段,因为IPostBackDataHandler,IPostBackEventHandler仅仅发生在页面生存周期的PostBack阶段。其实我们可以在PostBack做很多的事情,.net Framework认为大多数用户都希望处理Post回来的数据和事件,所以基于这个目的,他们为我们设计了IPostBackDataHandler和 IPostBackEventHandler这两个接口,这仅仅是微软的一个设计,所以没有什么特别神秘的。我们只要很好的理解他们的设计,就能让我们的 Control无缝的和所有基于.net Framework实现的其它Control协同工作。下面我将一步一步分析这两个接口的实现。
一、Page是什么?
当在Visual Stdio里面new一个Page的时候,生成的代码如下:
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
<%
![](http://www.cnblogs.com/Images/dot.gif)
@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="WebApplication1._Default" %>
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
<html xmlns="http://www.w3.org/1999/xhtml" >
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
<head runat="server">
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
<title>Untitled Page</title>
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
</head>
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
<body>
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
<form id="form1" runat="server">
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
<div>
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
</div>
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
</form>
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
</body>
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
</html>
从代码可以看出来,Page输出到客户端,它的内容区域就是在一个HTML的<form>元素。所以我们在页面上放的 TextBox,CheckBox,Button,还有很多的第三方的WebControl,它们都是在form元素里面的,最后输出到客户端,就会变为嵌入在<form>里面的Html节点,如果节点为input,这些都会变为表单的字段,例如<Input type="button" ...>,<Input type="text" ...>,<Input type="hidden" ...>.这里有一点值得注意的是,.net Framework常常会把ViewState,EvntTarget等一些需要在客户端保存的数据都作为一个type为hidden的input元素放在form里面。为什么这样做呢?因为<form>元素是一个很特殊的HTML元素。下面说说form:
form作为Html的一个元素,它就是为了客户端提交数据而产生的,它有两个很重要的属性action和method,action属性指明了处理提交的数据的应用程序的URL,而method有两个值:POST,GET,因为浏览器提交数据总是使用HTTP(也有使用HTTPS)协议,而 POST,GET则是HTTP协议传输数据的方式,所以method指明了传输数据的方式,对于一个新的Page所生成的html代码,form总是method=" POST"的方式提交数据(原因也有很多,比如数据安全性比Get高):如下
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
<html xmlns="http://www.w3.org/1999/xhtml" >
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
<head><title>
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
Untitled Page
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
</title></head>
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
<body>
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
<form name="form1" method="post" action="Default.aspx" id="form1">
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
<div>
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="/wEPDwUJNzgzNDMwNTMzZGQP0LJECgTtp1lOdVaW3IZPFDdsYw==" />
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
</div>
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
<div>
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
</div>
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
</form>
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
</body>
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
</html>
form上面所有的HTML规范定义的表单域(form field)元素,一旦具有name属性,在form进行submit的时候,form field(例如<input type ="text"..>)里面的数据都会自动被收集,然后按照一定的编码方式(如何编码?也有好多种啊,可以在form上设置,没空说了)进行编码,然后发给action定义的URL进行处理。
前面介绍了那么多关于form的知识,就是为了我们更好的理解Page的postback处理过程。所以说Page的核心就是一个Html 的<form>元素,它发生提交的时候总是以Post的方式把收集到的form field的值返回。具体关于<form>元素和Http协议,各位可以Google出很多的东西,这里就不详细说了。
二、Page的Post处理过程
当页面处理一个Http Post请求的时候,它会把form传回来数据进行解码,存入一个NameValueCollection的对象里面,我们可以通过 Request.Form来观察,这个存储结构比较类似于Hashtable,传入form field的name得到它的值。有了收集回来的post数据,就可以进行处理了。主要有两个Post的处理过程(参见《页面的生命周期》):一个在Init 阶段结束后,另一个在Load阶段后。ProcessRequest函数的代码片段如下:
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
// 1. PreInit
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
this.PerformPreInit();
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
// 2. Init
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
this.InitRecursive(null);
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
this.OnInitComplete(EventArgs.Empty);
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
// 对于Postback,插入下面处理
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
if (this.IsPostBack)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// 加载ViewState和ControlState,进行场景恢复
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
this.LoadAllState();
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// 第一次处理PostData
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
this.ProcessPostData(this._requestValueCollection, true);
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
// 3. PreLoad
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
this.OnPreLoad(EventArgs.Empty);
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
// 4. Load
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
this.LoadRecursive();
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
// 对于Postback,插入下面处理
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
if (this.IsPostBack)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// 第二次处理PostData
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
this.ProcessPostData(this._leftoverPostData, false);
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// 如果PostData表面某个Control数据发生变化,那么RaisePostDataChanged事件
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
this.RaiseChangedEvents();
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// RaisePostBackEvent
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
this.RaisePostBackEvent(this._requestValueCollection);
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
this.OnLoadComplete(EventArgs.Empty);
三、IPostBackDataHandler怎么工作的?
这个接口有两个方法:LoadPostData()和RaisePostDataChangedEvent(), 往往LoadPostData()会先被调用,如果返回true,那么代表数据发生变化,RaisePostDataChangedEvent()就会被调用,这样一个完整的Web Control的event就发出来了,例如TextBox的TextChanged就是这样发的。
先来分析Page页面是如何在请求处理函数里面来调用实现了IPostBackDataHandler接口的Control的,这个实现主要在Page的ProcessPostData函数,具体分析如下:
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
private void ProcessPostData(NameValueCollection postData, bool fBeforeLoad)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// 1. 用一个全局变量_changedPostDataConsumers来保存PostData发生
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// 变化的Control所有这些Control都要调用RaistPostDataChangedEvent()
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
if (this._changedPostDataConsumers == null)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
this._changedPostDataConsumers = new ArrayList();
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// 2. postData保存的是Form上的表单字段的value,可以通过表单字段的name的索引
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
if (postData != null)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
foreach (string str in postData)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// 对于系统定义的表单字段,直接跳过,例如:__VIEWSTATE
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
if ((str == null) || IsSystemPostField(str))
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
continue;
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// 获得这个表单字段对应的Control
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
Control control = this.FindControl(str);
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
if (control == null)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// 3. 这个标记为true,代表是在Load阶段前的调用,为false代表是
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// 在Load阶段后的调用其实这只是防止有些Control在Load阶段前
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// 还没有创建,所以在Load阶段后进行再一次调用而第二次调用
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// 处理的数据都是本次调用所无法处理的数据,本次成功处理的
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// Control,第二次调用都不会继续处理了。
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
if (fBeforeLoad)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
if (this._leftoverPostData == null)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
this._leftoverPostData = new NameValueCollection();
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
this._leftoverPostData.Add(str, null);
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
continue;
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// 程序走到这里,control不为null,因为如果为null,上面就continue了
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// 4. 取control.PostBackDataHandler或者PostBackEventHandler可以理
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// 解为把control as为IPostBackDataHandler 或者 IPostDataEventHandler
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// (注:真实逻辑还取adaper,但仅仅是为了Adapter机制,我们这里不用考虑)
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
IPostBackDataHandler postBackDataHandler = control.PostBackDataHandler;
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
if (postBackDataHandler == null)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// 5. 如果无法取到PostBackDataHandler,但是可以取得PostBackEventHandler,
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// 那么注册它。这个操作导致在后面的RaisePostBackEvent()函数会调用
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// 这个control的IPostBackEventHandler.RaisePostBackEvent()
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
if (control.PostBackEventHandler != null)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
this.RegisterRequiresRaiseEvent(control.PostBackEventHandler);
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
else
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// 6. postBackDataHandler不为null的时候,就调用它的LoadPostData()函数,
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// 如果返回结果为true,那么把该control加入_changedPostDataConsumers
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// (见注释1),这样在后面的RaiseChangedEvent里面就会依次从集合
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// _changedPostDataConsumers里面取出control,然后调用
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// control.RaisePostDataChangedEvent()
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
if ((postBackDataHandler != null) &&
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
postBackDataHandler.LoadPostData(str, this._requestValueCollection))
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
this._changedPostDataConsumers.Add(control);
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// 7. 如果这里处理了,就从_controlsRequiringPostBack集合从删除当前control
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// 的id,避免二次处理,实际上本函数就是处理两个集合,一个是传入的postData
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// 集合,另一个就是下面这个_controlsRequiringPostBack集合。这个集合里面的
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// control都是通过page的RegisterRequiresPostBack(Control control)方法注册
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// 进去的,这个集合会作为ControlState的一个附加字段存储,这样
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// LoadAllState的时候可以很好恢复。(见注释8)
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
if (this._controlsRequiringPostBack != null)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
this._controlsRequiringPostBack.Remove(str);
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// 8. 下面开始处理_controlsRequiringPostBack集合里面的control
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
ArrayList list = null;
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
if (this._controlsRequiringPostBack != null)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
foreach (string str2 in this._controlsRequiringPostBack)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
Control control2 = this.FindControl(str2);
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
if (control2 != null)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// (见注释4)
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
IPostBackDataHandler handler2 = control2.PostBackDataHandler;
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
if (handler2 == null)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
throw new HttpException(SR.GetString("Postback_ctrl_not_found", new object[]
![](http://www.cnblogs.com/Images/dot.gif)
{ str2 }));
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// (见注释6),对于PostBackData变化的Control加入
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// _changedPostDataConsumers集合
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
if (handler2.LoadPostData(str2, this._requestValueCollection))
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
this._changedPostDataConsumers.Add(control2);
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
continue;
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
else
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// control2为null,所以无法处理,加入集合,等待Load阶段后的调用处理(见注释3)
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
if (fBeforeLoad)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
if (list == null)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
list = new ArrayList();
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
list.Add(str2);
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
this._controlsRequiringPostBack = list;
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif)
}
对于Page注册的_controlsRequiringPostBack是如何保持到ControlState的,可以参考下面的代码片段:
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
private void SaveAllState()
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
if (this._needToPersistViewState)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// 1. 把ControlState存储到dictionary里面
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
.
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// 2. 把注册的需要PostBack处理的Control的id集合加入到用来保存ControlState
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// 的dictionary里面
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
if ((this._registeredControlsThatRequirePostBack != null) && (this._registeredControlsThatRequirePostBack.Count > 0x0))
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
dictionary.Add("__ControlsRequirePostBackKey__", this._registeredControlsThatRequirePostBack);
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// 3. 收集ViewState
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
.
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// 4. 把所有的State序列化到Page页面的hidden字段
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
.
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif)
}
通过上面的代码,我这里做一个小结:如果要写一个实现IPostBackDataHandler的Control,除了实现接口本身外,还必须做到下面两种方法的一种,才可以顺利完成任务:
第一种:该Control Render出来的元素本身就是一个表单域(form field),而且表单域的name和control的id保持一致,这样,Page在拿到表单域的数据后,可以通过name调用FindControl来找到相应的Control,然后如果Control.PostBackDataHandler 不为null,就进入调用入口。
第二种:该Control存放数据的表单域的name和该control的id并没有对应的关系,所以就需要在PreRender的时候(也可以在其它阶段,如Load等,不过大部分是在PreRender里面做),调用Page.RegisterRequiresPostBack(Control control) 方法,传入this作为参数,这样也可以保证Page会遍历所有注册过的Control,然后进入IPostBackDataHandler的调用入口。
综上所述,PostBackData,就是在客户端的一个数据缓存,当用户在客户端修改的时候,都是修改的数据缓存,不会和服务器通信,只有当form submit的时候,一次PostBack发生,然后缓存的数据会被form收集并传输到服务器端,服务器端就调用IPostBackDataHandler来处理传回的数据。
from:
http://www.cnblogs.com/joeliu/archive/2008/07/09/1237699.html
在我的上一篇文章《页面的生命周期》里面,我详细介绍了页面生存周期的各个阶段,但是对于PostBack阶段介绍的并不是很多,在本文里面我将详细补充介绍页面生存周期的PostBack 阶段,因为IPostBackDataHandler,IPostBackEventHandler仅仅发生在页面生存周期的PostBack阶段。其实我们可以在PostBack做很多的事情,.net Framework认为大多数用户都希望处理Post回来的数据和事件,所以基于这个目的,他们为我们设计了IPostBackDataHandler和 IPostBackEventHandler这两个接口,这仅仅是微软的一个设计,所以没有什么特别神秘的。我们只要很好的理解他们的设计,就能让我们的 Control无缝的和所有基于.net Framework实现的其它Control协同工作。下面我将一步一步分析这两个接口的实现。
一、Page是什么?
当在Visual Stdio里面new一个Page的时候,生成的代码如下:
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
<%
![](http://www.cnblogs.com/Images/dot.gif)
@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="WebApplication1._Default" %>
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
<html xmlns="http://www.w3.org/1999/xhtml" >
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
<head runat="server">
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
<title>Untitled Page</title>
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
</head>
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
<body>
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
<form id="form1" runat="server">
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
<div>
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
</div>
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
</form>
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
</body>
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
</html>
从代码可以看出来,Page输出到客户端,它的内容区域就是在一个HTML的<form>元素。所以我们在页面上放的 TextBox,CheckBox,Button,还有很多的第三方的WebControl,它们都是在form元素里面的,最后输出到客户端,就会变为嵌入在<form>里面的Html节点,如果节点为input,这些都会变为表单的字段,例如<Input type="button" ...>,<Input type="text" ...>,<Input type="hidden" ...>.这里有一点值得注意的是,.net Framework常常会把ViewState,EvntTarget等一些需要在客户端保存的数据都作为一个type为hidden的input元素放在form里面。为什么这样做呢?因为<form>元素是一个很特殊的HTML元素。下面说说form:
form作为Html的一个元素,它就是为了客户端提交数据而产生的,它有两个很重要的属性action和method,action属性指明了处理提交的数据的应用程序的URL,而method有两个值:POST,GET,因为浏览器提交数据总是使用HTTP(也有使用HTTPS)协议,而 POST,GET则是HTTP协议传输数据的方式,所以method指明了传输数据的方式,对于一个新的Page所生成的html代码,form总是method=" POST"的方式提交数据(原因也有很多,比如数据安全性比Get高):如下
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
<html xmlns="http://www.w3.org/1999/xhtml" >
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
<head><title>
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
Untitled Page
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
</title></head>
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
<body>
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
<form name="form1" method="post" action="Default.aspx" id="form1">
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
<div>
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="/wEPDwUJNzgzNDMwNTMzZGQP0LJECgTtp1lOdVaW3IZPFDdsYw==" />
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
</div>
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
<div>
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
</div>
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
</form>
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
</body>
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
</html>
form上面所有的HTML规范定义的表单域(form field)元素,一旦具有name属性,在form进行submit的时候,form field(例如<input type ="text"..>)里面的数据都会自动被收集,然后按照一定的编码方式(如何编码?也有好多种啊,可以在form上设置,没空说了)进行编码,然后发给action定义的URL进行处理。
前面介绍了那么多关于form的知识,就是为了我们更好的理解Page的postback处理过程。所以说Page的核心就是一个Html 的<form>元素,它发生提交的时候总是以Post的方式把收集到的form field的值返回。具体关于<form>元素和Http协议,各位可以Google出很多的东西,这里就不详细说了。
二、Page的Post处理过程
当页面处理一个Http Post请求的时候,它会把form传回来数据进行解码,存入一个NameValueCollection的对象里面,我们可以通过 Request.Form来观察,这个存储结构比较类似于Hashtable,传入form field的name得到它的值。有了收集回来的post数据,就可以进行处理了。主要有两个Post的处理过程(参见《页面的生命周期》):一个在Init 阶段结束后,另一个在Load阶段后。ProcessRequest函数的代码片段如下:
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
// 1. PreInit
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
this.PerformPreInit();
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
// 2. Init
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
this.InitRecursive(null);
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
this.OnInitComplete(EventArgs.Empty);
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
// 对于Postback,插入下面处理
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
if (this.IsPostBack)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// 加载ViewState和ControlState,进行场景恢复
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
this.LoadAllState();
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// 第一次处理PostData
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
this.ProcessPostData(this._requestValueCollection, true);
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
// 3. PreLoad
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
this.OnPreLoad(EventArgs.Empty);
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
// 4. Load
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
this.LoadRecursive();
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
// 对于Postback,插入下面处理
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
if (this.IsPostBack)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// 第二次处理PostData
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
this.ProcessPostData(this._leftoverPostData, false);
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// 如果PostData表面某个Control数据发生变化,那么RaisePostDataChanged事件
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
this.RaiseChangedEvents();
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// RaisePostBackEvent
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
this.RaisePostBackEvent(this._requestValueCollection);
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
this.OnLoadComplete(EventArgs.Empty);
三、IPostBackDataHandler怎么工作的?
这个接口有两个方法:LoadPostData()和RaisePostDataChangedEvent(), 往往LoadPostData()会先被调用,如果返回true,那么代表数据发生变化,RaisePostDataChangedEvent()就会被调用,这样一个完整的Web Control的event就发出来了,例如TextBox的TextChanged就是这样发的。
先来分析Page页面是如何在请求处理函数里面来调用实现了IPostBackDataHandler接口的Control的,这个实现主要在Page的ProcessPostData函数,具体分析如下:
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
private void ProcessPostData(NameValueCollection postData, bool fBeforeLoad)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// 1. 用一个全局变量_changedPostDataConsumers来保存PostData发生
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// 变化的Control所有这些Control都要调用RaistPostDataChangedEvent()
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
if (this._changedPostDataConsumers == null)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
this._changedPostDataConsumers = new ArrayList();
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// 2. postData保存的是Form上的表单字段的value,可以通过表单字段的name的索引
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
if (postData != null)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
foreach (string str in postData)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// 对于系统定义的表单字段,直接跳过,例如:__VIEWSTATE
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
if ((str == null) || IsSystemPostField(str))
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
continue;
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// 获得这个表单字段对应的Control
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
Control control = this.FindControl(str);
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
if (control == null)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// 3. 这个标记为true,代表是在Load阶段前的调用,为false代表是
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// 在Load阶段后的调用其实这只是防止有些Control在Load阶段前
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// 还没有创建,所以在Load阶段后进行再一次调用而第二次调用
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// 处理的数据都是本次调用所无法处理的数据,本次成功处理的
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// Control,第二次调用都不会继续处理了。
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
if (fBeforeLoad)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
if (this._leftoverPostData == null)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
this._leftoverPostData = new NameValueCollection();
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
this._leftoverPostData.Add(str, null);
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
continue;
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// 程序走到这里,control不为null,因为如果为null,上面就continue了
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// 4. 取control.PostBackDataHandler或者PostBackEventHandler可以理
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// 解为把control as为IPostBackDataHandler 或者 IPostDataEventHandler
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// (注:真实逻辑还取adaper,但仅仅是为了Adapter机制,我们这里不用考虑)
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
IPostBackDataHandler postBackDataHandler = control.PostBackDataHandler;
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
if (postBackDataHandler == null)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// 5. 如果无法取到PostBackDataHandler,但是可以取得PostBackEventHandler,
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// 那么注册它。这个操作导致在后面的RaisePostBackEvent()函数会调用
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// 这个control的IPostBackEventHandler.RaisePostBackEvent()
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
if (control.PostBackEventHandler != null)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
this.RegisterRequiresRaiseEvent(control.PostBackEventHandler);
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
else
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// 6. postBackDataHandler不为null的时候,就调用它的LoadPostData()函数,
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// 如果返回结果为true,那么把该control加入_changedPostDataConsumers
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// (见注释1),这样在后面的RaiseChangedEvent里面就会依次从集合
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// _changedPostDataConsumers里面取出control,然后调用
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// control.RaisePostDataChangedEvent()
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
if ((postBackDataHandler != null) &&
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
postBackDataHandler.LoadPostData(str, this._requestValueCollection))
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
this._changedPostDataConsumers.Add(control);
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// 7. 如果这里处理了,就从_controlsRequiringPostBack集合从删除当前control
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// 的id,避免二次处理,实际上本函数就是处理两个集合,一个是传入的postData
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// 集合,另一个就是下面这个_controlsRequiringPostBack集合。这个集合里面的
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// control都是通过page的RegisterRequiresPostBack(Control control)方法注册
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// 进去的,这个集合会作为ControlState的一个附加字段存储,这样
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// LoadAllState的时候可以很好恢复。(见注释8)
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
if (this._controlsRequiringPostBack != null)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
this._controlsRequiringPostBack.Remove(str);
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// 8. 下面开始处理_controlsRequiringPostBack集合里面的control
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
ArrayList list = null;
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
if (this._controlsRequiringPostBack != null)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
foreach (string str2 in this._controlsRequiringPostBack)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
Control control2 = this.FindControl(str2);
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
if (control2 != null)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// (见注释4)
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
IPostBackDataHandler handler2 = control2.PostBackDataHandler;
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
if (handler2 == null)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
throw new HttpException(SR.GetString("Postback_ctrl_not_found", new object[]
![](http://www.cnblogs.com/Images/dot.gif)
{ str2 }));
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// (见注释6),对于PostBackData变化的Control加入
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// _changedPostDataConsumers集合
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
if (handler2.LoadPostData(str2, this._requestValueCollection))
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
this._changedPostDataConsumers.Add(control2);
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
continue;
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
else
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// control2为null,所以无法处理,加入集合,等待Load阶段后的调用处理(见注释3)
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
if (fBeforeLoad)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
if (list == null)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
list = new ArrayList();
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
list.Add(str2);
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
this._controlsRequiringPostBack = list;
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif)
}
对于Page注册的_controlsRequiringPostBack是如何保持到ControlState的,可以参考下面的代码片段:
![](http://www.cnblogs.com/Images/OutliningIndicators/None.gif)
private void SaveAllState()
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
if (this._needToPersistViewState)
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// 1. 把ControlState存储到dictionary里面
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
.
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// 2. 把注册的需要PostBack处理的Control的id集合加入到用来保存ControlState
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// 的dictionary里面
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
if ((this._registeredControlsThatRequirePostBack != null) && (this._registeredControlsThatRequirePostBack.Count > 0x0))
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
{
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
dictionary.Add("__ControlsRequirePostBackKey__", this._registeredControlsThatRequirePostBack);
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// 3. 收集ViewState
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
.
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
// 4. 把所有的State序列化到Page页面的hidden字段
![](http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cnblogs.com/Images/dot.gif)
.
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
}
![](http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif)
}
通过上面的代码,我这里做一个小结:如果要写一个实现IPostBackDataHandler的Control,除了实现接口本身外,还必须做到下面两种方法的一种,才可以顺利完成任务:
第一种:该Control Render出来的元素本身就是一个表单域(form field),而且表单域的name和control的id保持一致,这样,Page在拿到表单域的数据后,可以通过name调用FindControl来找到相应的Control,然后如果Control.PostBackDataHandler 不为null,就进入调用入口。
第二种:该Control存放数据的表单域的name和该control的id并没有对应的关系,所以就需要在PreRender的时候(也可以在其它阶段,如Load等,不过大部分是在PreRender里面做),调用Page.RegisterRequiresPostBack(Control control) 方法,传入this作为参数,这样也可以保证Page会遍历所有注册过的Control,然后进入IPostBackDataHandler的调用入口。
综上所述,PostBackData,就是在客户端的一个数据缓存,当用户在客户端修改的时候,都是修改的数据缓存,不会和服务器通信,只有当form submit的时候,一次PostBack发生,然后缓存的数据会被form收集并传输到服务器端,服务器端就调用IPostBackDataHandler来处理传回的数据。
from:
http://www.cnblogs.com/joeliu/archive/2008/07/09/1237699.html
相关文章推荐
- IPostBackEventHandler 與 IPostBackDataHandler
- 服务器控件数据回发实现IPostBackDataHandler需注意的
- 组件开发之IPostBackDataHandler和OnLoad
- [Joe 原创] Web Control 开发系列(二) 深入解析Page的PostBack过程和IPostBackDataHandler
- asp.net组件(7)数据回发 IPostBackDataHandler
- Web Control 开发系列(二) 深入解析Page的PostBack过程和IPostBackDataHandler
- IPostBackDataHandler实现CollapablePanel控件的状态保持
- Web Control 开发系列(二) 深入解析Page的PostBack过程和IPostBackDataHandler
- Web Control 开发系列(二) 深入解析Page的PostBack过程和IPostBackDataHandler
- [Joe 原创] Web Control 开发系列(二) 深入解析Page的PostBack过程和IPostBackDataHandler
- web组件设计,利用接口(IPostBackDataHandler)产生数据回传的问题
- page在处理post请求时需要处理数据的加载IPostBackDataHandler和事件的触发IPostBackEventHandler.
- 【转】Web Control 开发系列(二) 深入解析Page的PostBack过程和IPostBackDataHandler
- 2 自定义控件之IPostBackDataHandler
- web组件设计,利用接口(IPostBackDataHandler)产生数据回传的问题
- 自定义控件(10)数据回传IPostBackDataHandler
- PHP Oracle Web Development: Data processing, Security, Caching, XML, Web Services, and Ajax (Paperback) Aug.2007.eBook-BBL
- 1.6.4 Uploading Structured Data Store Data with the Data Import Handler
- iOS Data Storage Guidelines 和 "do not back up"文件属性
- Circular view path : would dispatch back to the current handler URL again. Check your ViewResolver s