asp.net控件开发(二)实现回传之IPostBackEventHandle

本文深入剖析ASP.NET中的回传机制,包括回传的基本概念、IPostBackEventHandle接口的作用,以及通过UniqueID和脚本实现客户端事件到服务器端事件的映射过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

两个基本概念:
1、什么是回传?
回传就是HttpPost请求,或者在Url中带有数据的HttpGet请求,通过网页源代码可以看到:
method="post" action="页面名",这说明了即使是Get也会被转到Post。
2、IPostBackEventHandle接口的作用是什么?
接口的实质就是把客户端事件映射到服务器端事件,有两类映射方式:
1、通过UniqueID。
2、通过脚本。
通过两个例子分析两种映射方式:
一、通过UniqueID
SimpleButton,模拟Button实现事件回传,以UniqueID方式回传到服务器端

ContractedBlock.gif ExpandedBlockStart.gif
None.gif [
None.gif    
// The DefaultEventAttribute allows a page
None.gif    
// developer to attach a handler to the default
None.gif    
// event by double-clicking on the control.
None.gif
    DefaultEvent("Click"),
None.gif    DefaultProperty(
"Text"
None.gif    ]  
ExpandedBlockStart.gifContractedBlock.gif    
public class SimpleButton: WebControl, IPostBackEventHandler dot.gif{
InBlock.gif      
InBlock.gif        [
InBlock.gif        Bindable(
true),
InBlock.gif        Category(
"Behavior"),
InBlock.gif        DefaultValue(
""),
InBlock.gif        Description(
"The text to display on the button")
InBlock.gif        ]
ExpandedSubBlockStart.gifContractedSubBlock.gif        
public virtual string Text dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif            
get dot.gif{
InBlock.gif                
string s = (string)ViewState["Text"];
InBlock.gif                
return((s == null? String.Empty : s);
ExpandedSubBlockEnd.gif            }

ExpandedSubBlockStart.gifContractedSubBlock.gif            
set dot.gif{
InBlock.gif                ViewState[
"Text"= value;
ExpandedSubBlockEnd.gif            }

ExpandedSubBlockEnd.gif        }

InBlock.gif        
protected override void LoadViewState(object savedState)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
base.LoadViewState(savedState);
ExpandedSubBlockEnd.gif        }

InBlock.gif        
protected override void TrackViewState()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
base.TrackViewState();
ExpandedSubBlockEnd.gif        }

InBlock.gif        
protected override void LoadControlState(object savedState)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
base.LoadControlState(savedState);
ExpandedSubBlockEnd.gif        }

InBlock.gif        
protected override void OnLoad(EventArgs e)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
base.OnLoad(e);
ExpandedSubBlockEnd.gif        }

InBlock.gif        
protected override void OnInit(EventArgs e)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
base.OnInit(e);
ExpandedSubBlockEnd.gif        }

InBlock.gif        
protected override object SaveControlState()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
return base.SaveControlState();
ExpandedSubBlockEnd.gif        }

InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif        
protected override HtmlTextWriterTag TagKey dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif            
get dot.gif{
InBlock.gif                
return HtmlTextWriterTag.Input;
ExpandedSubBlockEnd.gif            }

ExpandedSubBlockEnd.gif        }

InBlock.gif        
InBlock.gif        [
InBlock.gif        Category(
"Action"),
InBlock.gif        Description(
"Raised when the button is clicked")
InBlock.gif        ]
InBlock.gif        
public event EventHandler Click;
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif        
protected override void AddAttributesToRender(HtmlTextWriter writer) dot.gif{                  
InBlock.gif            
base.AddAttributesToRender(writer);
InBlock.gif            writer.AddAttribute(HtmlTextWriterAttribute.Name,
this.UniqueID);
InBlock.gif            writer.AddAttribute(HtmlTextWriterAttribute.Type,
"Submit"); 
InBlock.gif            writer.AddAttribute(HtmlTextWriterAttribute.Value, 
this.Text);           
ExpandedSubBlockEnd.gif        }
 
InBlock.gif      
InBlock.gif        
// Method of IPostBackEventHandler that raises postback events.
ExpandedSubBlockStart.gifContractedSubBlock.gif
        void IPostBackEventHandler.RaisePostBackEvent(string eventArgument)dot.gif{        
InBlock.gif            OnClick(EventArgs.Empty);
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
// Invokes delegate registered with the Click event.
ExpandedSubBlockStart.gifContractedSubBlock.gif
        protected virtual void OnClick(EventArgs e) dot.gif{       
ExpandedSubBlockStart.gifContractedSubBlock.gif            
if (Click != nulldot.gif{
InBlock.gif                Click(
this, e);
ExpandedSubBlockEnd.gif            }
 
ExpandedSubBlockEnd.gif        }

InBlock.gif      
ExpandedSubBlockStart.gifContractedSubBlock.gif        
protected override void Render(HtmlTextWriter writer) dot.gif{
InBlock.gif            
// Ensures that this control is nested in a server form.
ExpandedSubBlockStart.gifContractedSubBlock.gif
            if (Page != nulldot.gif{
InBlock.gif                Page.VerifyRenderingInServerForm(
this);
ExpandedSubBlockEnd.gif            }

InBlock.gif            
base.Render(writer);
ExpandedSubBlockEnd.gif        }

ExpandedBlockEnd.gif    }
 

让我们看看客户端单击事件是如何发送到服务器的:
首先,让我们从页面被编译成类似App_web_tingluzi.dll的临时文件开始说起,在此之前Application内部类CallHandlerExecutionStep的Excute()方法执行后,会转到Page的生命期。经过一系列的ProcessRequest、编译(JIT)App_web_tingluzi.dll临时文件,然后就会编译(JIT)我们写的控件的程序集了本例中是SimpleButton.dll,正式进入控件的生命期。(如果有Global,会在web页前被编译为Global.dll)
如果想了解详细的信息可以看dudu的:
解读System.Web.UI.Page中关键方法ProcessRequestMain()
注:基于1.1,不过基本的东西还是一样的
http://www.cnblogs.com/dudu/archive/2005/10/21/259328.html
ASP.NET 2.0运行时简要分析
http://www.cnblogs.com/dudu/archive/2006/01/14/317016.html
客户端事件映射到服务器端事件的流程:
从Page的核心方法ProcessRequestMain()开始,它处理Page的整个生命期(详细的可看dudu的分析)。
现在只关注和回传有关的内容,下面是涉及到回发的页面生命期,从Init结束开始:
1、LoadAllState
(包含LoadPageStateFromPersistenceMedium,LoadViewStateRecursive)
2、ProcessPostData //通过判断控件是否实现PostBackEventHandler标记其是否引发Postback
3、PreLoad(非PostBack)
4、Load(非PostBack)
5、ProcessPostData
6、RaiseChangedEvents
7、RaisePostBackEvent//通过显示接口调用客户端的RaisePostBackEvent,并且实现了两类绑定:UniqID和客户端脚步
下面深入的了解一下Pages是如何实现自动映射的:
首先是ProcessPostData方法,他保证了回传能够正确的进行,是回传的基础:
下面是有关ProcessPostData的伪代码:
参数说明:postDate:Form回发给服务器的内容包含form中引起回传的控件、RequestQury的值、_VIEWSTATE、以及通过脚本回传给服务期的数据。通过Page.RequestValueCollection可以看到集合的值。

None.gif // postData指:Page.RequestValueCollection。bool标记是Load前调用的还是load后调用的
None.gif
private  IPostBackEventHandler _registeredControlThatRequireRaiseEvent;
None.gif
private   void  ProcessPostData(NameValueCollection postData,  bool  fBeforeLoad)
None.gifIPostBackDataHandler handler1 
=  control1.PostBackDataHandler;
None.gif                            
if  (handler1  ==   null )
ExpandedBlockStart.gifContractedBlock.gif                            
dot.gif {
InBlock.gif                                
if (control1.PostBackEventHandler != null)
ExpandedSubBlockStart.gifContractedSubBlock.gif                                
dot.gif{
InBlock.gif                                    
this.RegisterRequiresRaiseEvent(control1.PostBackEventHandler);
ExpandedSubBlockEnd.gif                                }

ExpandedBlockEnd.gif                            }

None.gif[EditorBrowsable(EditorBrowsableState.Advanced)]
None.gif        
public   virtual   void  RegisterRequiresRaiseEvent(IPostBackEventHandler control)
ExpandedBlockStart.gifContractedBlock.gif        
dot.gif {
InBlock.gif            
this._registeredControlThatRequireRaiseEvent = control;
ExpandedBlockEnd.gif        }

Page会在postDate中寻找实现PostBackEventHandler接口的控件,如果找到就把他赋值给_registeredControlThatRequireRaiseEvent。这样在 RaisePostBackEvent(NameValueCollection postData)中就实现了通过UniqID把客户端事件映射到服务端。
下面看RaisePostBackEvent方法,下面是伪代码:
RaisPostBackEvent()是Page的方法和PostbackEventHandler接口的方法没有关系。
None.gif private   void  RaisePostBackEvent(NameValueCollection postData)
ExpandedBlockStart.gifContractedBlock.gif        
dot.gif {
InBlock.gif        
//ProcessPostData已经把实现PostBackEventHandler接口的控件标记为可PostBack了
InBlock.gif
            if (this._registeredControlThatRequireRaiseEvent != null)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif        
//通过UniqID映射
InBlock.gif
                this.RaisePostBackEvent(this._registeredControlThatRequireRaiseEvent, null);
ExpandedSubBlockEnd.gif            }

InBlock.gif            
else
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif        
//通过脚步回传映射
InBlock.gif
                string text1 = postData["__EVENTTARGET"];
InBlock.gif                
bool flag1 = !string.IsNullOrEmpty(text1);
InBlock.gif                
if (flag1 || (this.AutoPostBackControl != null))
ExpandedSubBlockStart.gifContractedSubBlock.gif                
dot.gif{
InBlock.gif                    Control control1 
= null;
InBlock.gif                    
if (flag1)
ExpandedSubBlockStart.gifContractedSubBlock.gif                    
dot.gif{
InBlock.gif                        control1 
= this.FindControl(text1);
ExpandedSubBlockEnd.gif                    }

InBlock.gif                    
if ((control1 != null&& (control1.PostBackEventHandler != null))
ExpandedSubBlockStart.gifContractedSubBlock.gif                    
dot.gif{
InBlock.gif                        
string text2 = postData["__EVENTARGUMENT"];
InBlock.gif                        
this.RaisePostBackEvent(control1.PostBackEventHandler, text2);
ExpandedSubBlockEnd.gif                    }

ExpandedSubBlockEnd.gif                }

InBlock.gif                
else
ExpandedSubBlockStart.gifContractedSubBlock.gif                
dot.gif{
InBlock.gif                    
this.Validate();
ExpandedSubBlockEnd.gif                }

ExpandedSubBlockEnd.gif            }

ExpandedBlockEnd.gif        }

None.gif[EditorBrowsable(EditorBrowsableState.Advanced)]
None.gif        
protected   virtual   void  RaisePostBackEvent(IPostBackEventHandler sourceControl,  string  eventArgument)
ExpandedBlockStart.gifContractedBlock.gif        
dot.gif {
InBlock.gif
//注意下面是显式接口调用,sourceControl被转换成了IPostBackEventHandler
InBlock.gif
            sourceControl.RaisePostBackEvent(eventArgument);
ExpandedBlockEnd.gif        }

在这个方法内部实现了两种映射,在有两个参数的重载中通过显式接口方法调用了子控件的RaisePostBackEvent,引发了子控件定义的服务器事件。
二、通过脚本
NavButtons,提供了向前和向后两个事件的导航按钮,因为有两个事件,事件通过委托链实现。
ContractedBlock.gif ExpandedBlockStart.gif
None.gif// NavButtons.cs
None.gif
// Developing Microsoft ASP.NET Server Controls and Components
None.gif
// Copyright ?2002, Nikhil Kothari and Vandana Datye
None.gif
//
None.gif

None.gif
using System;
None.gif
using System.ComponentModel;
None.gif
using System.Web.UI;
None.gif
using System.Web.UI.WebControls;
None.gif
None.gif
ExpandedBlockStart.gifContractedBlock.gif
namespace MSPress.ServerControls dot.gif{
InBlock.gif    
InBlock.gif    
// The NavButtons control renders two HTML buttons and generates
InBlock.gif    
// JavaScript to cause postback. Upon postback,
InBlock.gif    
// the control uses the value of the argument passed into 
InBlock.gif    
// the RaisePostBackEvent method to determine which
InBlock.gif    
// HTML element caused postback.
InBlock.gif    
//
InBlock.gif
    [
InBlock.gif    DefaultEvent(
"ClickNext"),
InBlock.gif    DefaultProperty(
"NextText")
InBlock.gif    ]
ExpandedSubBlockStart.gifContractedSubBlock.gif    
public class NavButtons: WebControl, IPostBackEventHandler dot.gif{
InBlock.gif        
InBlock.gif        
private static readonly object EventClickNext = new object();
InBlock.gif        
private static readonly object EventClickPrevious = new object();
InBlock.gif              
InBlock.gif        [
InBlock.gif        Bindable(
true),
InBlock.gif        Category(
"Behavior"),
InBlock.gif        DefaultValue(
""),
InBlock.gif        Description(
"The text to display on the Next button")
InBlock.gif        ]
ExpandedSubBlockStart.gifContractedSubBlock.gif        
public virtual string NextText dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif            
get dot.gif{
InBlock.gif                
string s = (string)ViewState["NextText"];
InBlock.gif                
return((s == null? String.Empty : s);
ExpandedSubBlockEnd.gif            }

ExpandedSubBlockStart.gifContractedSubBlock.gif            
set dot.gif{
InBlock.gif                ViewState[
"NextText"= value;
ExpandedSubBlockEnd.gif            }

ExpandedSubBlockEnd.gif        }

InBlock.gif        
InBlock.gif        [
InBlock.gif        Bindable(
true),
InBlock.gif        Category(
"Behavior"),
InBlock.gif        DefaultValue(
""),
InBlock.gif        Description(
"The text to display on the Previous button")
InBlock.gif        ]
ExpandedSubBlockStart.gifContractedSubBlock.gif        
public virtual string PreviousText dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif            
get dot.gif{
InBlock.gif                
string s = (string)ViewState["PreviousText"];
InBlock.gif                
return((s == null? String.Empty : s);
ExpandedSubBlockEnd.gif            }

ExpandedSubBlockStart.gifContractedSubBlock.gif            
set dot.gif{
InBlock.gif                ViewState[
"PreviousText"= value;
ExpandedSubBlockEnd.gif            }

ExpandedSubBlockEnd.gif        }

InBlock.gif        
InBlock.gif        [
InBlock.gif        Category(
"Action"),
InBlock.gif        Description(
"Raised when the Next button is clicked")
InBlock.gif        ]
ExpandedSubBlockStart.gifContractedSubBlock.gif        
public event EventHandler ClickNext dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif            add 
dot.gif{
InBlock.gif                Events.AddHandler(EventClickNext, value);
ExpandedSubBlockEnd.gif            }

ExpandedSubBlockStart.gifContractedSubBlock.gif            remove 
dot.gif{
InBlock.gif                Events.RemoveHandler(EventClickNext, value);
ExpandedSubBlockEnd.gif            }

ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        [
InBlock.gif        Category(
"Action"),
InBlock.gif        Description(
"Raised when the Previous button is clicked")
InBlock.gif        ]
ExpandedSubBlockStart.gifContractedSubBlock.gif        
public event EventHandler ClickPrevious dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif            add 
dot.gif{
InBlock.gif                Events.AddHandler(EventClickPrevious, value);
ExpandedSubBlockEnd.gif            }

ExpandedSubBlockStart.gifContractedSubBlock.gif            remove 
dot.gif{
InBlock.gif                Events.RemoveHandler(EventClickPrevious, value);
ExpandedSubBlockEnd.gif            }

ExpandedSubBlockEnd.gif        }
   
InBlock.gif
InBlock.gif        
// Invokes delegates registered with the ClickNext event.
ExpandedSubBlockStart.gifContractedSubBlock.gif
        protected virtual void OnClickNext (EventArgs e) dot.gif
InBlock.gif            EventHandler clickNextHandler 
= (EventHandler)Events[EventClickNext];
ExpandedSubBlockStart.gifContractedSubBlock.gif            
if (clickNextHandler != nulldot.gif{
InBlock.gif                clickNextHandler(
this, e);
ExpandedSubBlockEnd.gif            }
  
ExpandedSubBlockEnd.gif        }
 
InBlock.gif     
InBlock.gif        
// Invokes delegates registered with the ClickPrevious event.
ExpandedSubBlockStart.gifContractedSubBlock.gif
        protected virtual void OnClickPrevious (EventArgs e) dot.gif
InBlock.gif            EventHandler clickPreviousHandler 
= (EventHandler)Events[EventClickPrevious];
ExpandedSubBlockStart.gifContractedSubBlock.gif            
if (clickPreviousHandler != nulldot.gif{
InBlock.gif                clickPreviousHandler(
this, e);
ExpandedSubBlockEnd.gif            }
  
ExpandedSubBlockEnd.gif        }
 
InBlock.gif
InBlock.gif        
// Method of IPostBackEventHandler that raises postback events.
ExpandedSubBlockStart.gifContractedSubBlock.gif
        void IPostBackEventHandler.RaisePostBackEvent(string eventArgument)dot.gif{
InBlock.gif            
if (eventArgument == "Previous")
InBlock.gif                OnClickPrevious(EventArgs.Empty);
InBlock.gif            
else if (eventArgument == "Next")
InBlock.gif                OnClickNext(EventArgs.Empty);
ExpandedSubBlockEnd.gif        }

InBlock.gif      
ExpandedSubBlockStart.gifContractedSubBlock.gif        
protected override void Render(HtmlTextWriter writer) dot.gif{
InBlock.gif            
// Ensures that this control is nested in a server form.
ExpandedSubBlockStart.gifContractedSubBlock.gif
            if (Page != nulldot.gif{
InBlock.gif                Page.VerifyRenderingInServerForm(
this);
ExpandedSubBlockEnd.gif            }

InBlock.gif            
base.Render(writer);
ExpandedSubBlockEnd.gif        }

InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif        
protected override void RenderContents(HtmlTextWriter writer) dot.gif{
InBlock.gif            writer.AddAttribute(HtmlTextWriterAttribute.Onclick, Page.GetPostBackEventReference(
this"Previous"));
InBlock.gif            writer.AddAttribute(
"language""javascript");
InBlock.gif            writer.RenderBeginTag(HtmlTextWriterTag.Button);
InBlock.gif            writer.Write(
this.PreviousText);
InBlock.gif            writer.RenderEndTag();
InBlock.gif
InBlock.gif            writer.AddAttribute(HtmlTextWriterAttribute.Onclick, Page.GetPostBackEventReference(
this"Next"));
InBlock.gif            writer.AddAttribute(
"language""javascript");
InBlock.gif            writer.RenderBeginTag(HtmlTextWriterTag.Button);
InBlock.gif            writer.Write(
this.NextText);
InBlock.gif            writer.RenderEndTag();
ExpandedSubBlockEnd.gif        }
      
ExpandedSubBlockEnd.gif    }
    
ExpandedBlockEnd.gif}

None.gif
None.gif
这种绑定的实现和UniqueID类似,主要区别是,Page类的RaisPostBackEvent方法通过检测PostDate是否含有"__EVENTTARGET","__EVENTARGUMENT"来实现客户端事件到服务器的映射,见else部分的代码。
ClientScriptManager.GetPostBackClientHyperlink的作用:
1、生成回传的Javascrip和两个隐藏域
2、生成调用Javascrip的脚本,可以把它和Html特性绑定
注:编译指运行时编译,编译(JIT)指jit编译
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值