Asp.net文本框事件简介
博主花园的一个兄弟问我一个问题,动态创建的控件是如何加载视图状态的,还提到了ProcessPostData方法的调用。这里我将使用TextBox的TextChanged事件来讨论视图数据的加载和事件的触发。我们先来看一个演示:代码如下:。
运行结果如下:。
现在让我们修改文本框的值,然后点击按钮提交页面,看看会发生什么。
此时发生了TextBox的TextChanged事件,运行结果如下图所示:。
现在我们什么都不做,点击按钮再次提交,看看会有什么效果:。
这是为什么了,文本框的文本已更改事件这时候没有触发。大家是否知道文本框的文本已更改事件触发的条件了,那好我们今天就一起来看看该事件是如何触发的。这里我们首先来看看文本框的定义:复制代码代码如下:公共类TextBox : WebControl,IPostBackDataHandler,IEditableTextControl,ITextControl公共接口IPostBackDataHandler { bool LoadPostData(字符串postDataKey,namevalucollection post collection);void raisepostdatanagedevent();}公共接口IEditableTextControl : ITextControl {事件处理程序TextChanged}公共接口ITextControl {字符串文本{ get设置;} } 这里我们最主要的是关注IPostBackDataHandler接口的实现,复制代码代码如下:受保护的虚拟bool LoadpostDataKey(字符串命名值集合后置集合){ base .ValidateEvent(PostDataKey);字符串文本=这个。文字;string str 2=post collection[PostDataKey];if(!这个。只读!文字等于(str2,StringComparison .序数)){这个文本=str2返回真;}返回false}受保护的虚拟void raiseposstdatanagementdevent(){ if(this .自动回邮!这个页面。ispostbaceventcontrolregistered){ this .页面。AutoPostBackControl=这个如果(这个。原因验证){这个.页面。验证(这validation GrouP);} }这个contextchanged(EventArgs .空的);} 这里的RaisePostDataChangedEvent方法比较好理解,主要就是调用文本已更改事件方法,而LoadPostData方法中是可以取到文本框当前值(旧值字符串文本=这个。文字;)和邮政过来的新值(后收集[postDataKey]),如果当前文本框不是只读,并且新旧值不等的话,则吧新值赋给文本框的文本属性,返回没错,否者返回假的,这里我们能否猜测文本框的LoadPostData返回没错,我们才调用RaisePostDataChangedEvent方法。在前面的ASP。网佩奇事件处理管道我们曾经提到两段比较特殊的代码,一段是处理IPostBackDataHandler一段是处理IPostBackEventHandler。首先我们还是来先看看复制代码代码如下:这OnInitComplete(EventArgs .空的);如果(上下文TraceIsEnabled) {这个.追踪。写(' aspx.page ',' End InitComplete ');}如果(这个IsPostBack) { if (context .TraceIsEnabled) { this .追踪。写(' aspx.page ',' Begin LoadState ');}这个loadall state();如果(上下文TraceIsEnabled) {这个.追踪。写(' aspx.page ',' End LoadState ');这个追踪。Write('aspx.page ',' Begin ProcessPostData ');}这个ProcessPostData(这. requestValueCollection,true);如果(上下文TraceIsEnabled) {这个.追踪。Write('aspx.page ',' End ProcessPostData ');} }如果(上下文TraceIsEnabled) {这个.追踪。Write('aspx.page ',' Begin PreLoad ');}这个. OnPreLoad(事件参数。空的);这一段吧,在InitComplete之后、预载之前我们这里在处理IPostBackDataHandler接口,这里主要是一个LoadAllState和ProcessPostData方法。首先我们需要知道这里的_requestValueCollection是一个什么东西,其实很简单,如果是邮政主要是这个。_请求。表单(其中有些过滤处理,如过滤掉__VIEWSTATE ',__EVENTTARGET),如果是得到请求有查询字符串集合则是这个。_请求。查询字符串就是这个。_请求。查询字符串。
LoadAllState的主要带代码如下:复制代码代码如下:查看代码?private void loadall state(){ object obj 2=this .loadpagestateformpersistenceinmedia();IDictionary first=null第二对=nullPair pair2=obj2为配对;if (obj2!=null) { first=pair2 .首先作为IDictionarysecond=pair2 .第二对;}如果(第一!=null) {这个._ controls requiring back=(ArrayList)第一个[' _ _个控件需要回发键_ _ '];如果(这个_ registeredcontrolrequired control state!=null) { foreach(在(IEnumerable)中的控制控件)这个_ registeredcontrolrequired control state){ control .loadcontrolstationinternal(第一个[控件. UniqueID]);} } }如果(秒!=null) {字符串s=(字符串)秒。第一;int num=int .解析,NumberFormatInfo .不变量信息);这个_fPageLayoutChanged=num!=这个gettypeshashcode();if(!这个_fPageLayoutChanged) { base .LoadViewStateRecursive(秒。第二);} } }受保护的内部虚拟对象loadpagestateformpersistencimedia(){ page statepister page statepister=this .页面状态持久器请尝试{ pageStatePersister .load();} catch(HttpeException异常){如果(这个)._ page flags[8]){ 0返回null}异常WebEventCode=0xbba扔;}返回新的对(页面状态持久器.控制状态,页面状态持久. ViewState);}内部void LoadChildViewStateByID(ArrayList子状态){ int count=子状态.计数;for(int I=0;我数;I=2){ string id=(string)子状态[I];对象savedState=子状态[I 1];控制控制=这个find CONtrol(id);如果(控制!=null) { control .loadviewstattre草书(SavedState);} else { this .ensuremeetinglfields();如果(这个_偶尔机场.ControlsViewState==null) { this ._偶尔机场.ControlsViewState=new Hashtable();}这个_偶尔机场.控制视图状态[id]=SavedState;} } } LoadAllState方法注意到是加载每个控件的控制状态和视图状态数据,数据来源是通过loadpagestateformpersistenceinmedia方法获得的,数据类容就是上次反应中各控件的控制状态数据和视图状态数据。
接下来我们该看看ProcessPostData方法,复制代码代码如下: private void ProcessPostData(NameValueCollection Postdata,bool fBeforeLoad) { if (this ._ changedpostdata consumers==null){ this ._ changedpostdata consumers=new ArrayList();} if (postData!=null){ foreach(PostDATa中的字符串字符串){ if ((str!=null)!IsSystemPostField(str)){ Control Control=this .FindControl(字符串);if(control==null){ if(FBEforeload){ if(this ._ leftopostdata==null){ this ._ left opostdata=new NameValueCollection();}这个_ leftoverPostData .添加(字符串,null);} } else { IPostBackDataHandler=回发数据处理程序=控件.postbackdathandlerif(postbackdathandler==null){ if(control .PostBackEventHandler!=null) {这个.RegisterRequiresRaiseEvent(控件postbackeeventhandler);} } else { if (postBackDataHandler!=null) { NameValueCollection后置集合=控件calculateffectivvalidaterequest()?这个_requestValueCollection :此_ unvalidateddrequestvaluecollection;if (postBackDataHandler .LoadPostData(str,postCollection)) {这个._changedPostDataConsumers .添加(控制);} }如果(这._控制快速回发回发!=null) {这个._控制快速回发回发。移除(字符串);} } } } } } ArrayList列表=null如果(这个_ controls快速回发回发!=null) { foreach(本例中为字符串str2 ._控制快速回发回发){控制控制2=这个.find CONtrol(字符串2);如果(控制2!=null){ IPostBackDataHandler适配器内部=控件2 .内部适配器作为IPostBackDataHandlerif(adapterInternal==null){ adapterInternal=控件2作为IPostBackDataHandler} if(adapterInternal==null){ 0引发新的HttpException(SR.GetString('回发_ctrl_not_found ',新对象[]{ str 2 });} NameValueCollection值2=控件2 .calculateffectivvalidaterequest()?这个_requestValueCollection :此_ unvalidateddrequestvaluecollection;if (adapterInternal .LoadPostData(str2,值2)){ 0这_changedPostDataConsumers .添加(控件2);} } else if(fbbeforefload){ if(list==null){ list=new ArrayList();}列表add(str 2);} }这个_ controlsRequiringPostBack=list } }首先根据创建来的参数NameValueCollection的键来查找我们的控制控件,一般情况下控件是可以找到的,但是在负荷中动态创建的控件这里是找不到的。这个方法分为两部分,以数组列表列表=null这句代码分开,一部分如果中不到控制控件处理比较简单,如果找到看看它是不是PostBackDataHandler类型,如果不是并且它的PostBackEventHandler不为空,那么我们直接调用它的这个RegisterRequiresRaiseEvent(控件PostBackEventHandler)方法,如果是PostBackEventHandler类型的控件我们直接调用它的LoadPostData方法,复制代码代码如下:if (postBackDataHandler .LoadPostData(str,postCollection)) {这个._changedPostDataConsumers .添加(控制);} 同时从_控制快速回发集合中移除该控件复制代码代码如下:if(这个_ controls快速回发回发!=null) {这个._控制快速回发回发。移除(字符串);} 该方法的第二部分是遍历控件快速回发中的集合,它的处理方式和上面一部分类似,只是没有找到控件的编号则记录下来复制代码代码如下: else if(fBeforeLoad){ if(list==null){ list=new ArrayList();}列表add(str 2);} 默认情况下_控制快速回发是包含动态创建的控件。这里我们也说说这个集合吧,控件快速回发的设置是在LoadAllState方法中的这一句代码:这个_ controls requiring back=(ArrayList)第一个[' _ _个控件需要回发键_ _ '];有LoadAllState(加载数据状态)就有SaveAllState(保存数据状态),在保存状态中有这么一句代码:字典。添加(“_ _个控件需要回发键_ _”)这个_ registeredcontrolharequired back);其中_ registeredcontroltaprequired back集合定义在registered需要spostback方法中。
复制代码代码如下:公共void registerrequires spostback(控件控件){ if(!(控件是IPostBackDataHandler)!(控制内部适配器是IPostBackDataHandler)){ 0抛出新的HttpException(SR . GetString(' Ctrl _ not _ data _ handler ');}如果(这个_ registeredcontrolstaequiredback==null){ this ._ registeredcontrolasequiredback=new ArrayList();}这个_ registeredcontrolthaptrequiredback .添加(控件. UniqueID);} 总之在这里动态添加的控件是没办法加载数据的,但是其它默认的控件在这里都可以处理。现在我们来看看控件是如何添加的,在控制类中有一个添加的控件方法是真正添加控件的处理:复制代码代码如下:受保护的内部虚拟无效添加的控件(控件控件,整数索引){ if(控件.OwnerControl!=null){ 0抛出新的无效的操作异常(SR . GetString(' replacement _ NotAllowed ');} if (control ._家长!=null) { control ._家长。控件。移除(控件);}控制_ parent=这个控制_page=这个.页面;控制。旗帜。清除(0x 20000);控件命名容器=这个。标志[0x 80]?这个:这个. naming container if(naming container!=null) { control .UpdateNamingContainer(namingContainer);if(控制_id==null)!control.flags[0x40]) { control .generate automatic id();} else if ((control ._id!=null) ||(控件。_控件!=null)) { namingContainer .DirtyNameTable();} }如果(这._controlState=ControlState .children initialized){ 0控件InitRecursive(命名容器);if(((控制_controlState=ControlState .已初始化()控件。稀有场!=null))控件。稀有字段要求控制状态){这.佩奇。registerrequires controllstate(控件);}如果(这个_controlState=ControlState .view station loaded){ 0对象savedState=null如果((这个。_事故场!=null()这_偶尔机场.ControlsViewState!=null)) { savedState=this ._偶尔机场.控制视图状态[索引];如果(这个LoadViewStateByID){ 0控件EnsureID();保存状态=这个._偶尔机场.控件视图状态[控件身份证】;这个_偶尔机场.控件视图状态。移除(控件身份证);} else { savedState=this ._偶尔机场.控制视图状态[索引];这个_偶尔机场.控件视图状态。移除(索引);} }控件loadviewstattre草书(SavedState);如果(这个_controlState=ControlState .已加载){控制.LoadRecursive();如果(这个_controlState=ControlState .预渲染){控件.PreRenderRecursiveInternal();} } } } }在这个方法中有调用这个页面。registerrequires controllstate(控件)和控制。加载视图状态递归(保存状态)方法,一个负责控制状态一个负责视图状态的数据加载,当我们这里第2次和3次邮政请求时,在负荷创建textboxt控件就会加载它已有的控件状态和视图状态。现在我们再来看看ProcessRequestMain中处理IPostBackEventHandler的那段带代码:复制代码代码如下:这LoadRecursive();如果(上下文TraceIsEnabled) {这个.追踪。写(' aspx.page ',' End Load ');}如果(这个IsPostBack) { if (context .TraceIsEnabled) { this .追踪。写入(' aspx.page ',' Begin processpost data Second Try ');}这个ProcessPostData(这. leftopostdata _ false);如果(上下文TraceIsEnabled) {这个.追踪。写入(' aspx.page ',' End processpost data Second Try ');这个追踪。写(' aspx.page ',' Begin Raise ChangedEvents ');}这个raisechangggeevents();如果(上下文TraceIsEnabled) {这个.追踪。写(' aspx.page ',' End Raise ChangedEvents ');这个追踪。Write('aspx.page ',' Begin Raise post back事件');}这个RaisePostBackEvent(这. requestValueCollection);如果(上下文TraceIsEnabled) {这个.追踪。写(' aspx.page ',' End Raise post back事件');} }如果(上下文TraceIsEnabled) {这个.追踪。写(' aspx.page ',' Begin LoadComplete ');}这个在线加载完成(事件参数).空的);首先我们来看看_ leftoverPostData集合是什么,它是在先前一次调用ProcessPostData方法时没有找到控件的一个编号集合。
在这里就可以找到该控件,执行路线主要就是数组列表=空这句后面部分,最终还是要调用复制代码代码如下:if(适配器内部.LoadPostData(str2,值2)){ 0这_changedPostDataConsumers .添加(控件2);} 这个方法,这里第二次调用ProcessPostData方法主要就就是处理动态创建控件的事件问题。这里我们再来看看RaiseChangedEvents方法吧:复制代码代码如下:内部void raisechanggeevents(){ if(this ._changedPostDataConsumers!=null){ for(int I=0;我喜欢这个_changedPostDataConsumers .计数;I){ 0控制控制=(控制)这个_ changedpostdata消费者[I];如果(控制!=null){ IPostBackDataHandler=回发数据处理程序=控件.postbackdathandlerif(((control==null)| | control .是(this)的后代(((control!=null()控件PostBackDataHandler!=null))) { postBackDataHandler .raiseepstdata changedevent();} } } } } 我想到这里文本框的文本已更改事件的执行你应该很清楚了吧。而RaisePostBackEvent方法就不说,看代码大家都会明白的,复制代码代码如下: private void RaisePostBackEvent(NameValueCollection PostDATa){ if(this ._ registeredcontrolhatrequiraiseevent!=null) {这个.RaisePostBackEvent(这. registeredcontrolhatrequireseievent,null);} else { string str=PostDATa[' _ _ EVENTTARGET '];弯曲件标志=!字符串IsNullOrEmpty(字符串);if (flag || (this .AutoPostBackControl!=null)){ 0控制控件=nullif (flag) { control=this .FindControl(字符串);} if ((control!=null()控件PostBackEventHandler!=null)){ string EVENT参数=PostDATa[' _ _ EVENT参数'];这个RaisePostBackEvent(控件PostBackEventHandler,eventArgument);} } else { this .验证();} } }到这里我们在回忆一下,一般控件的状态信息保存是通过保存状态方法,而加载状态信息是在InitComplete之后、预载之前的LoadAllState方法,加载的数据就是上次请求保存状态方法保存的数据,加载状态后调用ProcessPostData方法来处理邮政过来的数据,动态添加的控件在第二次及后面每次请求添加时都会加载状态数据,说直接一点是动态添加的控件在添加的时候就加载它的状态数据。在负荷之后、加载完成之前就是我们处理控件的事件调用问题,这里我们再次调用ProcessPostData用来处理动态创建的控件与邮政过来的数据,之后分别调用RaiseChangedEvents、RaisePostBackEvent方法拉起处理IPostBackDataHandler、IPostBackEventHandler中的事件调用。
版权声明:Asp.net文本框事件简介是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。