asp.net页面处理流程 - 2 (Preload, Load, LoadComplete)

如果你看了这篇文章而没有看之前的文章,那还是建议你看一看;因为光看这一篇文章,你很难明白我到底想说些啥;


前面说到,对于我们的例子页面,可能大家都忘记了例子页面了;
<div><asp:Label ID="Label1" runat="server" Text="Label"></asp:Label></div>
<asp:Repeater ID="Repeater1" runat="server">
            <HeaderTemplate>
                <asp:CheckBox ID="HeadCheckBox" runat="server" Text="Head"/>
            </HeaderTemplate>
</asp:Repeater>
protected void Page_Load(object sender, EventArgs e)
    {
        this.Repeater1.DataSource = new object[] { };
        this.Repeater1.DataBind(); 


        var CheckBox4 = new CheckBox();
        CheckBox4.ID = "DynamicCheckBox";
        CheckBox4.Text = CheckBox4.ID;
        CheckBox4.AutoPostBack = true;
        CheckBox4.CheckedChanged += ck_CheckedChanged;
        this.form1.Controls.Add(CheckBox4);
        


         CheckBox ck = (CheckBox) Repeater1.Controls[0].Controls[1];
         ck.AutoPostBack = true;
         ck.CheckedChanged += ck_CheckedChanged;
    }   
    protected void ck_CheckedChanged(object sender, EventArgs e)
    {
        CheckBox cb = (CheckBox)sender;
        var lbText = cb.ClientID + (cb.Checked ? " checked" : " not checked") + ":"+cb.Text;
        this.Label1.Text = lbText;
    }  
页面很简单,问题也很简单,Repeater中Header行的CheckBox改变状态时不会触发 ck_CheckedChanged 方法;
而动态创建的CheckBox改变状态时则会触发,why?


在Page类的ProcessReques调用 OnPreLoad 之前,Repeater中根据PostBack回来的ViewState中的数据,已经重新构建了提交前页面中的Child Controls;
并且,Page类的一个私有变量 _changedPostDataConsumers 里面已经记录了Repeater控件Header行这个CheckBox控件;
理论上,不出意外的话,在 Page_Load之后,会触发事件的;


现在先看看 OnPreLoad 函数, OnPreLoad处理相当简单,看看当前Page类注册了哪些PreLoad事件,然后一个个调用
有的子控件会在OnInit中给Page的PreLoad增加自己的PreLoad事件处理;例如 Repeater控件;
总之,子控件增加的PreLoad事件应该在父控件的PreLoad事件之前触发;


OnPreLoad之后,调用LoadRecursive 函数,也就是 OnLoad了;
和PreLoad的处理顺序正好相反,父控件的Load事件将在子控件的Load事件之后触发;
LoadRecursive 这个函数就是递归调用本控件的OnLoad函数以及所有子控件的LoadRecursive 函数;
页面你所写的Page_Load函数也就在这个时候被调用了;
本来以为,在 Page_Load的
        this.Repeater1.DataSource = new object[] { };
        this.Repeater1.DataBind(); 
这两句代码执行后,Page类的这个私有变量_changedPostDataConsumers 中就会没有原来LoadViewState方法产生的那个 CheckBox了,结果发现还在;
在整个OnLoad执行完后,依旧还在;
不管,我们继续往下看,看到底啥时候这个创建了又因为Repeaer重新绑定数据源而无声无息被删除了的CheckBox被从_changedPostDataConsumers 中删除;


好,OnLoad也完成了,轮到哪儿了?大家猜猜;估计很多人会猜测错误;
不是 OnLoadComplete ,而先要干另外一点事情;


判断IsPostBack为true,
1。再次以如下方式调用ProcessPostData函数:
this.ProcessPostData(this._leftoverPostData, false)函数;
大家如果看过我上一篇文章而且确实好记性的话(我很佩服你,因为过了两天,我就不记得这个函数的第二个参数表示啥意思了);
第一个参数反而记得,在处理Request提交过来的参数时,如果根据名称找到了控件,则该控件将该名称对应的值利用LoadPosData进行调用;
而如果找不到控件,呵呵,将名称加到  _leftoverPostData 中;这儿的this.ProcessPostData就是干这个事情的了;
所以,动态创建的CheckBox在选中状态改变时,在这次调用时ProcessPostData能够设置选中状态,并在之后的后续处理中触发CheckedChanged事件了;


2。接着上面的  this.ProcessPostData(this._leftoverPostData, false)函数之后,就是 RaiseChangedEvents 方法了;
触发页面上控件的各种事件处理了;但是,呵呵,_changedPostDataConsumers 此时是有那个 
因为LoadViewState在Repeater中创建又因为Repeaer重新绑定数据源而无声无息被删除了的CheckBox的呃;
仔细看看 RaiseChangedEvents  方法,你会发现这样一句话:
 if (((control == null) || control.IsDescendentOf(this)) && ((control != null) && (control.PostBackDataHandler != null)))
                        
{                           postBackDataHandler.RaisePostDataChangedEvent();
   
}
就是这个判断 control.IsDescendentOf(this)   使得  _changedPostDataConsumers 中存放的CheckBox不会触发任何事件的了;


3。接着RaiseChangedEvents,就是 RaisePostBackEvent 了;
   这个函数,会干啥呢?判断 ["__EVENTTARGET"] 对应的控件会否是一个PostBackEventHandler属性不为null的控件,例如
    按钮,LinkButon,ImageButton 等等;    
    由此大家也可以看出,如果有一个 CheckBox,设置了CheckedChanged事件,但没有设置AutoPostBack属性,
                      还有一个按钮,设置了 OnClick 事件,
    则,改变CheckBox  选中状态,点击按钮,将首先触发CheckedChanged事件,再触发 OnClick 事件     




然后,就到了页面的 OnLoadComplete 了;触发 LoadComplete 事件;


终于,PreLoad,Load,LoadComplete 也完成了;


至于,Render之类的,我就不多说了;
PreRender事件 父控件将先 PreRender,然后子控件 PreRender,
然后调用页面的 PreRenderComplete 事件;
然后调用页面的 SaveAllState 产生所有控件的ViewState构成的Pair对象数,并序列化成byte[]类型,然后利用Base64编码;
然后触发页面的 然后调用页面的 SaveStateComplete 事件;
呵呵,所以,如果你在 SaveStateComplete 中修改了 Label的Text,你会发现提交回来后修改将不记得你的修改;
再然后,调用页面的 RenderControl 方法,将页面以及所有子控件输出到浏览器去;




到了这儿,我也可以顺便和大家解释一下动态控件的事件触发机制了,
上面的代码中,
 this.form1.Controls.Add(CheckBox4);   //这一句话干了很多事情;
 还记得我们的 LoadViewState中,
 Pair的Second的格式吗?
 [子控件的序号,子控件的Pair,子控件的序号,子控件的Pair...]
如果子控件的序号大于当前子控件的数量?例如,当前页面的静态控件数量只有1个,
如果你在在Page_Load中动态创建了CheckBox,则这个动态创建的CheckBox将占据2的控件序号,
但在LoadViewState时,在Page中当然找不到序号为2的这个控件(因为此时还没有调用LoadRecursive 函数,
所以[2,序号为2的子控件的Pair] 将放到一个变量  _occasionalFields 中;
当调用LoadRecursive 的时候,会调用页面的 Page_Load方法,
这个方法中 
运行 this.form1.Controls.Add(CheckBox4); 时,
根据新增加的这个控件的序号,到 _occasionalFields 去找该序号对应的Pair,
如果找到,则调用该控件的 LoadViewStateRecursive 方法来加载提交前页面产生的ViewState来恢复提交前页面的状态;
在 LoadRecursive  完成后,判断IsPostBack为true,再次以如下方式调用ProcessPostData函数:
 this.ProcessPostData(this._leftoverPostData, false)函数;
这次,对于这个动态添加的CheckBox, 将根据Post回来的值设置状态;此时,将登记这个CheckBox的CheckedChanged状态;






  


















  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值