.net组件开发系列之武术系列 武术招数 控件生命周期与控件事件机制
一。控件生命周期
先回述上篇,可能表述没有不清晰,也可能跨度大了点,好的,我们来一个循序渐进过程,大家都知道,武术都有招术的,先出什么,再出什么,什么时候打完收工,都是有顺序的,而我们的控件也正如此,它也有一个顺序。那我们的这个顺序(控件的生命周期)是怎么的.在web这个无状态http协议的通信中,如何实现了,如何创建一个象webform程序那样呢。使页面提供一个连续执行的。答案是。在处理完一个请求之后保存其状态,在回传时,在新的请求之前恢复已保存的状态。
页面(其实也是一个控件,继承webcontrol)把请求分成几个阶段,能够用于重新创建和保存页面及控件树。那好,我们来看看控件生命期图:
(ps:画得不乍的)
关于控件生命周期各个阶段所发生的事,网上很多很多,详见:
http://blog.csdn.net/SysBug/archive/2007/06/04/1638013.aspx(很详细的)
我们的主要在于分析执行机制,分了说明其执行顺序,我们举个例先:
我们在这样做的。就是重写控件生命周期的每个阶段,并且写入一些简单消息,然后,我们分三种。我们先将控件直接注册到页面上,一种是动态注册控件,一种是实例化控件,但不加到控件树上。然后通过启用trace="true"去页面追踪.
先了一个控件,代码如下:
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
/**//// <summary>
/// ConDemo 的摘要说明
/// </summary>
///
namespace cnblogs
{
public class ConDemo : Control
{
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
Page.Trace.Warn(this.UniqueID, "在初始化阶段");
}
protected override void TrackViewState()
{
base.TrackViewState();
Page.Trace.Write(this.UniqueID, "在加载视图。。。");
}
protected override void LoadViewState(object savedState)
{
base.LoadViewState(savedState);
Page.Trace.Write(this.ID, "在保存视图阶段");
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
Page.Trace.Write(this.UniqueID, " 在加载中。。。");
}
protected override object SaveViewState()
{
Page.Trace.Write(this.UniqueID, " 在保存视图状态..");
return base.SaveViewState();
}
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
Page.Trace.Write(this.UniqueID, "在预呈现");
}
protected override void Render(HtmlTextWriter writer)
{
Page.Trace.Write(this.UniqueID, "在呈现..");
base.Render(writer);
}
public override void Dispose()
{
base.Dispose();
}
public ConDemo()
{
//
// TODO: 在此处添加构造函数逻辑
//
}
}
}
然后在aspx 写上如下代码
注意:记得启动 Trace="true"
<%@ Page Language="C#" Trace="true" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<%@ Register Namespace="cnblogs" TagPrefix="tt" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>无标题页</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<tt:ConDemo runat=server ID="Condemo1"></tt:ConDemo>
<%--控件添加 --%>
<asp:Button ID="Button1" runat="server" Text="加载控件" OnClick="Button1_Click" />
<%--产生回传 --%>
<asp:Button ID="Button2" runat="server" Text="postback" /></div>
</form>
</body>
</html>
在cs页面
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void Button1_Click(object sender, EventArgs e)
{
cnblogs.ConDemo dy = new cnblogs.ConDemo();
dy.ID="dynamic1";
this.Controls.Add(dy);
cnblogs.ConDemo dy2=new cnblogs.ConDemo();
dy2.ID="dynamic2";
}
}
这些工作做完后,我们来分析分析现象。当我在第一次在浏览器浏览时:我们发现,子控件会在在预览的时候,可以发现阶段Condemo1(自定义控件)的执行顺序,当它被加到父控件的Controls里时,父控件会根据其当前的control阶段来调用该子控件的一些方法,让子控件赶上父控件的control阶段,
(图1)
每一个控件内部都保存着它当前的加载进度,也就是它到达了上述的哪一个阶段,当我们执行Control.Controls.Add方法来将一个控件添加到另一个控件中时,父控件就会检查子控件的加载进度,如果子控件的加载进度比自己的慢了,就会要求子控件追赶上来,
当我们点击"加载控件"按钮时,发现:
(两张图是一起的,截图的时候的不好截)
(图2)
蓝色代表,是动态添加的,红色是我们在页面上直接注册的。
但我们在button 事件还创建了一个自定义控件(dynamic2)实例,可我们没有把它添加到控件树上,所以说,除非控件添加到控件树上,否则它不将参于请求处理,当在页面上注册控件时,页面的解析器会把它加到控件树上,动态创建的控件,则要自已将控件添加到控件树上。
从上面图中,我们还可以看到,另一个信息,就是我们为什么动态添加的控件在回传后会消失,从图中,一眼就看出来了,按图2来说吧,因为当dynamic1动态加载到控件树上时,可这个控件树(这里指的是Page页面)已经完成了加载视图状态,从而在后来的恢复视图中找不到了dynamic1中的视图了。这样就解析了动态控件回传后为什么会消失的问题,经过分析,你可能已经知道了,我们点了"postback"按扭后,控件树,变成什么样了吧。
现在问题出现了,该如何解决呢?
介绍两种方法吧:
第一种,就是在OnInit事件中动态加载进去,
示例:
protected override void OnInit(EventArgs e)
{ cnblogs.ConDemo dy= new cnblogs.ConDemo();
dy.ID="dynamic1";
this.Controls.Add(dy);
dy.Visible = false;
base.OnInit(e);
}
然后在按扭事件中。查找dynamic1控件,将其Visible为true
第二种,见我的(动态添加控件终极解决方案)
地址:http://www.cnblogs.com/suiqirui19872005/archive/2007/10/11/920845.html
二:下一讲事件机制,
原本想今天写事件机制一并写掉,可我没有准备好示例,所以,等下一讲讲吧。
先透露一下,大家都常用IPostBackDataHandler,IPostBackEventHandler了吧,
下一讲还有两个事件注册。GetPostBackClientHyperlink,GetPostBackEventReference
我们都用过LinkButton吧,我们发现其生成html后,成了
javascript:__doPostBack('LinkButton1',''),其中就用了GetPostBackClientHyperlink,下一节中,将讲到。
PS:自已的表达能力差了点,望大家海含,我在更正当中。