.net控件开发(五)之 深入理解控件的呈现原理

  首言

ASP.NET控件基本上都是继承Framework 已有三个基类,Control,WebControl,CompositeControl下面我就各个基类的呈现方法
      讲述
Control,WebControl, CompositeControl各自的呈现过程。
   

第一个:Control呈现过程。

Control所继承的控件的输出流程:

在正常的控件呈现输出(就是说不是ajax控件里,ajax会打乱此图)中,它是一个循环调用的过程,看看下面的图就知道了
 

现在来分析分析其实现过程,在Render方法中调用另外一个名为RenderChildren的受保护成员,

该方法接收服务器控件内容的 HtmlTextWriter对象.

protected internal virtual void Render(HtmlTextWriter writer)
{
    
this.RenderChildren(writer);
}

protected internal virtual void RenderChildren(HtmlTextWriter writer)
{
/*
在这里this.occasionalFields中,它实现了OccasionalFields类,此类是一个sealed类,也就是一个不可继承的类,在其类中有一个Controls的public属性,返回的是一个控件集(ControlCollection)
在此处是用于维护其子控件列表的集合容器。

*/

ICollection children 
= (this._occasionalFields == null? null : ((ICollection) this._occasionalFields.Controls);

    
this.RenderChildrenInternal(writer, children);
}

 

在此,我们什么时候给了this._occasionalFields赋值了呢。赋了什么值呢。当加入到控件树上时(使用了findControl查找控件),它会调用一个


private void EnsureNamedControlsTable
方法(这个方法在
findControl中调用)去确保所有控件都被正确加载完成。
然后将其填充在一个控件集中
this.FillNamedControlsTable(thisthis._occasionalFields.Controls);,
从这里开始注意了,Ajax异步回调与正常输出的控件是从这里开始分岐的。
 1internal void RenderChildrenInternal(HtmlTextWriter writer, ICollection children)
 2{
 3/*
 4this.RareFields如果设置这个参数,意谓着以自定义的方式去改写RenderChildern
 5没有的话,将进行默态的流程对所有的子控件进行处理。
 6
 7*/

 8    if ((this.RareFields != null&& (this.RareFields.RenderMethod != null))
 9{
10   /*调用RenderMethod委托,Asp.net Ajax在使用Control.SetRenderMethodDelegate时,对应的回调函数就是在此时处理的
11关于ajax的控件程现流程详见: http://www.cnblogs.com/liuxu-wxy/archive/2007/04/25/727346.html
12
13 */

14        writer.BeginRender();
15        this.RareFields.RenderMethod(writer, this);
16        writer.EndRender();
17    }

18    else if (children != null)
19{
20 //如果不设置这个RareFieldsEnsured,会把所有的控件呈现                
21        //依次调用Control里所有子控件的RenderControl               
22        foreach (Control control in children)
23        {
24            control.RenderControl(writer);//完成子控件的呈现过程
25        }

26    }

27}

28
 

接下来就是真正呈现过程的入口方法

//该方法为入口方法
public virtual void RenderControl(HtmlTextWriter writer)
{
    
this.RenderControl(writer, this.Adapter);
}


下面这段代码,这个是一个过渡代码,其中的this.flags[0x10]没有搞明白是什么一回事,但不要紧。
它都会去调用
 RenderControlInternal方法

RenderControlInternal代码段
下面代码。控件是否有相关的呈现适配器,有的话就适配器调用适配器的相关呈现方法
private void RenderControlInternal(HtmlTextWriter writer, ControlAdapter adapter)
{
    
if (adapter != null)
{  
//调用相关的适配器方法
        adapter.BeginRender(writer);
        adapter.Render(writer);
        adapter.EndRender(writer);
    }

    
else
    
{
        
this.Render(writer);
    }

}

     理解就是:
1.
控件开始呈现
2.
控件是否有相关的呈现适配器,有的话就适配器调用适配器的相关呈现方法
3.
呈现子控件
4.
完成控件呈现

 

第二个:WebControl呈现过程

WebControl:Control的基础上增加了Style,呈现方面就是在Render(HtmlTextWriter writer) 方法中扩展了三个呈现方法,增加一个属性呈现方法

流程图如下:

伪代码如下:
    

  public virtual void RenderBeginTag(HtmlTextWriter writer)
        
{
            
this.AddAttributesToRender(writer);
            
//呈现Tag开始标记
        }


        
protected override void Render(HtmlTextWriter writer)
        
{
            
//重写了Control的Render方法并增加了三个扩展方法
            this.RenderBeginTag(writer);
            
this.RenderContents(writer);
            
this.RenderEndTag(writer);
        }

        
protected internal virtual void RenderContents(HtmlTextWriter writer)
        
{
            
//调用Control的呈现
            base.Render(writer);
        }


        
public virtual void RenderEndTag(HtmlTextWriter writer)
        
{
            
//呈现结束标记
        }


        
protected virtual void AddAttributesToRender(HtmlTextWriter writer)
        
{
            
//呈现Attribute
        }

 

 

第三个:CompositeControl呈现过程

   CompositeControl类是一个抽象类,为自定义控件提供命名容器和控件设计器功能,该自定义控件包含全部子控件或使用其他控件功能。此类由Login Wizard 等控件继承

复合控件类必须派生自System.Web.UI.WebControls.CompositeControl类。这一点与ASP.NET 1.x环境下开发复合控件有些不同。在ASP.NET 1.x中,复合控件必须实现System.Web.UI.INamingContainer接口。然而,在ASP.NET 2.0下,复合控件类的基类则发生了变化

public abstract class CompositeControl : WebControl, INamingContainer, ICompositeControlDesignerAccessor

  其余使用以后再讲,今天主要是讲其呈现过程;

CompositeControl 重写了WebControlRender(HtmlTextWriter writer),增加了设计时支持以创建子控件  

 protected internal override void Render(HtmlTextWriter writer)
        
{
            
//如果在设计时,创建子控件,也就是在设计时增加友好体验
            if (DesignMode)
                   
this.EnsureChildControls();
            
base.Render(writer);
        }

————————————————————————————————————

后述:

.net控件开发系列文章

1.net组件开发系列()之武术系列-----------马步功   之基本功
2.
net组件开发系列()之武术系列--------太极拳 开发ajax控件
3.
.net组件开发系列之武术系列武术招数控件生命周期与控件事件机制
4.
.net控件开发系列事件处理机制三个接口两个方法



坐断江南 笑煞之!!
posted @ 2007-10-18 14:32 坐断东南 笑煞之!! 阅读(2729) 评论(11)  编辑 收藏 所属分类: 组件设计系列

  回复  引用  查看    
#1楼 2007-10-18 17:31 | 丰色日月      
最近也在看Control的代码。this.flags[0x10]标志位表示控件是否是可见的。0x10这些标志数字都是常量来的。
  回复  引用  查看    
#2楼 [楼主]2007-10-18 17:33 | 坐断东南 笑煞之!!      
谢谢指点,我看了半天,
不知道这个flags[0x10]代表什么。。
  回复  引用    
#3楼 2007-10-19 09:48 | 征途私服 [未注册用户]
写得好,顶一下
  回复  引用    
#4楼 2007-10-19 13:52 | liuxu-wxy [未注册用户]
写的不错,关于[0x10]是这样的
this.flags是SimpleBitVector32结构,类似于存放了大量控制标记(标识当前的流程状态)

private const int styleSheetApplied = 0x4000; //字段 标识当前控件已经使用了脚本样式
private const int themeApplied = 0x400; //字段 标识当前控件已经使用了主题
private const int useGeneratedID = 0x200000; //字段 标识当前控件已经使用了自动生成列

protected virtual void TrackViewState()
{
//调用追踪视图状态
if (this._viewState != null)
{
this._viewState.TrackViewState();
}
//设置追踪视图状态标记
this.flags.Set(2);
}

在Control.Visible中
public virtual bool Visible
{
get
{
//如果已经设置了不可见,直接返回false
if (this.flags[0x10])
{
return false;
}

if ((this._parent != null) && !this.DesignMode)
{
return this._parent.Visible;
}
return true;
}
set
{
//判断了如果当前已经设置了追踪视图状态标记
if (this.flags[2])
{
//如果第一次设置Visble 为false,flag返回 true
//flag不等于value,设置标记为0x20
bool flag = !this.flags[0x10];
if (flag != value)
{
this.flags.Set(0x20);
}
}

if (!value)
{
//设置不可见
this.flags.Set(0x10);
}
else
{
this.flags.Clear(0x10);
}
}
}

以上,你就会发现,当Visible设置为false时,会设置标记0x10,0x20
在RenderControl()方法中,如果当前Visible是false,是不会向客户端发送任何信息的,如,您把一个Button设置为Visible false,在客户端是看不见它的


  回复  引用  查看    
#5楼 [楼主]2007-10-19 14:16 | 坐断东南 笑煞之!!      
TO: liuxu-wxy
够详细的,谢谢你详细的解释
  回复  引用    
#6楼 2007-10-19 17:36 | Andy@CHY [未注册用户]
不錯,好文!!
  回复  引用    
#7楼 2007-10-19 20:27 | liuxu-wxy [未注册用户]
我的mail地址是 liuxu_wxy@hotmail.com,
您有联系方式吗,看来是志同道合的朋友,想跟您一起探讨一下asp.net ,可否将联系方式发到我的邮箱中
  回复  引用    
#8楼 2007-11-07 12:41 | sdds [未注册用户]
建议楼主把哪些讨厌的广告都删除了,惹人烦!
  回复  引用  查看    
#9楼 [楼主]2007-11-07 13:16 | 坐断东南 笑煞之!!      
已删了。。



标题  
姓名  
主页
Email (只有博主才能看到) 
验证码 *  看不清,换一张 [登录][注册]
内容(请不要发表任何与政治相关的内容)  
  登录  使用高级评论  新用户注册  返回页首  恢复上次提交      
该文被作者在 2007-10-18 14:42 编辑过