您的位置:首页 > 编程语言 > ASP

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

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

前面说到,对于我们的例子页面,可能大家都忘记了例子页面了;

<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  完成后,判断IsPos
4000
tBack为true,再次以如下方式调用ProcessPostData函数:

 this.ProcessPostData(this._leftoverPostData, false)函数;

这次,对于这个动态添加的CheckBox, 将根据Post回来的值设置状态;此时,将登记这个CheckBox的CheckedChanged状态;

  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  asp.net