用户在ASP.NET应用程序显示的页面上面点击一个Button、LinkButton、或者改变某个TextBox的Value时(启用AotuPostBack),就会导致页面提交,并且在服务器端引发对应的PostBack事件,大家可以想象客户端浏览器显示的是html,而html是不存在引发PostBack事件这一说的,这样就说明ASP.NET应用程序肯定提供一种方法,能够知道用户在客户端做了什么动作导致页面被提交的,然后服务器端根据这个信息引发相应的服务器端控件的PostBack事件,那么这篇文章,我们一起来讨论下ASP.NET应用程序是如何来引发PostBack事件.
首先我们通过最直接的方式来查看ASP.NET Page 根据什么信息来引发对应控件的PostBack事件的,我们知道 页面继承与 Page类,服务器端接受到一个页面请求时,服务器端会按预期的进行一系列的处理,这个就是Page 页面的生命周期,在这里我们就不讨论这个内容的,因为已经有很多文章介绍Page生命周期的内容的,这里我们只关注Page类型中RaisePostBackEvent方法里面的逻辑,我们通过Reflector查看 Page类型的RaisePostBackEvent方法.
private void RaisePostBackEvent (NameValueCollection postData)
{
if (this._registeredControlThatRequireRaiseEvent != null)
{
this.RaisePostBackEvent(this._registeredControlThatRequireRaiseEvent, null);
}
else
{
string str = postData["__EVENTTARGET"];
bool flag = !string.IsNullOrEmpty(str);
if (flag || (this.AutoPostBackControl != null))
{
Control control = null;
if (flag)
{
control = this.FindControl(str);
}
if ((control != null) && (control.PostBackEventHandler != null))
{
string eventArgument = postData["__EVENTARGUMENT"];
this.RaisePostBackEvent(control.PostBackEventHandler, eventArgument);
}
}
else
{
this.Validate();
}
}
}
这段代码做这样几件事情,首先判断是否页面上有某个控件注册引发PostBack事件,通常通过Page.RegisterRequiresPostBack(Control control)方法来注册的,如果没有控件注册引发PostBack事件,那么就会查看回传页面的post数据中是否包含这样2个键值对,__EVENTTARGET 和 __EVENTARGUMENT,如果__EVENTTARGET键包含值,那么通过Page.FindControl找到控件的引用并查看该控件PostBackEventHandler是否为空,不为空那么就引发这个控件的PostBackEvent,这个就是ASP.NET如何引发页面回传事件的逻辑啦.
对于第一种方式在服务器端为某个控件注册需要引发回传事件,这通常是在我们开发的完全定制自定义控件中需要使用的(完全定制也就是不组合已有的服务器端控件),通过在自定义的控件中实现IPostBackEventHandler 和 IPostBackDataHandler 接口, IPostBackDataHandler接口需实现2个方法 bool LoadPostData(string postDataKey, NameValueCollection postCollection) 和 void RaisePostDataChangedEvent().我们需要在LoadPostData 方法中判断回发数据是否包含你想要的信息(页面提交会将form中的信息以key-value的形式提交到服务器,在这里我们只需要判断key-value集合中是否包含对应控件的Name属性即可),如果包含我们想要的信息,那么就说明是我们自定义的控件引发的回传,这样则可将这个控件注册为需要引发回传事件.
对于第二种方式,比如像LinkButton控件,其呈现时生成的Html代码不是<input type="submit"/>,因此他本身是不具备提交页面的功能,因此客户端必须通过JavaScript来实现页面提交,但是由于LinkButton呈现的html代码是<a>标签,页面提交时并不会将<a>标签key-value进行打包,所以页面提交后,服务器端无法找到到底是谁引发的页面回传,因此ASP.NET提供2个Hidden Input标签.
<input type="hidden" name="__EVENTTARGET" id="__EVENTTARGET" value="" />
<input type="hidden" name="__EVENTARGUMENT" id="__EVENTARGUMENT" value="" />
这2个东东相信大家经常看到,当你点击LinkButton时,客户端会通过JavaScript将被点击的LinkButton的Name和对应的参数存储在这2个hidden input中,然后提交页面,页面会将这2个hidden input 打包,以key-value的形式传回到服务器端,服务器端就可以通过 postData["__EVENTTARGET"] 来获取究竟是什么引发页面回传,进而找到其对应的服务端控件并触发其回传事件.