一、Control的呈现过程

在上个章节““生死有序”的控件生命周期”中,我们提到Render是控件开发的主角,但在控件树的“合成模式(Composite)”部分这位主角却缺席了(戏份太多的缘由)。哦,好吧。主角现在登场。

1)控件树呈现的“合成模式(Composite)”

控件树的呈现过程是一个华丽的大圈,它从RenderControl(HtmlTextWriter writer)开始、从RenderChildrenInternal(HtmlTextWriter writer, ICollection children)结束。其过程涉及Control类的6个方法。期间种种,我们慢慢道来。

public virtual void RenderControl(HtmlTextWriter writer);

protected void RenderControl(HtmlTextWriter writer, ControlAdapter adapter);

private void RenderControlInternal(HtmlTextWriter writer, ControlAdapter adapter);

protected internal virtual void Render(HtmlTextWriter writer);

protected internal virtual void RenderChildren(HtmlTextWriter writer);

internal void RenderChildrenInternal(HtmlTextWriter writer, ICollection children);

①Page中RenderControl()的调用:故事开始的地方

我们知道,Page类实现了IHttpHandler接口,所以ASP.NET框架得以最终把对请求进行响应的任务通过调用Page的ProcessRequest()方法交给aspx页面。在Page执行ProcessRequest()方法处理请求时,它完成了大量的工作:维持状态、处理回传数据、处理事件等等,而最后一个环节是基于HttpContext中Response.Output流创建HtmlTextWrite,并调用Page从Control类那里继承来的RenderControl()方法把页面内容发送给请求者。

//......呈现的入口

this.RenderControl(this.CreateHtmlTextWriter(this.Response.Output));

②RenderControl(HtmlTextWriter writer):

 

[TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]

public virtual void RenderControl(HtmlTextWriter writer)

{

    this.RenderControl(writer, this.Adapter);

}

③RenderControl(HtmlTextWriter writer, ControlAdapter adapter):

protected void RenderControl(HtmlTextWriter writer, ControlAdapter adapter)

{

    if (this.flags[16] || this.flags[512])     //if(this.Visible == false):详见下面附的代码

    {

        this.TraceNonRenderingControlInternal(writer);

        return;

    }

    HttpContext httpContext = (this.Page == null) ? null : this.Page._context;

    if (httpContext != null && httpContext.TraceIsEnabled)

    {

        int bufferedLength = httpContext.Response.GetBufferedLength();

        this.RenderControlInternal(writer, adapter);

        int bufferedLength2 = httpContext.Response.GetBufferedLength();

        httpContext.Trace.AddControlSize(this.UniqueID, bufferedLength2 - bufferedLength);

        return;

    }

    this.RenderControlInternal(writer, adapter);

}

[Bindable(true), DefaultValue(true), WebCategory("Behavior"), WebSysDescription("Control_Visible")]

public virtual bool Visible

{

    get

    {

        return !this.flags[16] && (this._parent == null || this.DesignMode || this._parent.Visible);

    }

    set

    {

        if (this.flags[2])

        {

            bool flag = !this.flags[16];

            if (flag != value)

            {

                this.flags.Set(32);

            }

        }

        if (!value)

        {

            this.flags.Set(16);

            return;

        }

        this.flags.Clear(16);

    }

}

private const int invisible = 16;

private const int notVisibleOnPage = 512;

④RenderControlInternal(HtmlTextWriter writer, ControlAdapter adapter):

private void RenderControlInternal(HtmlTextWriter writer, ControlAdapter adapter)

{

    try

    {

        this.BeginRenderTracing(writer, this);

        if (adapter != null)   //控件是否有相关的呈现适配器

        {

            //如果有,呈现适配器调用相关的呈现方法呈现控件

            adapter.BeginRender(writer);

            adapter.Render(writer);

            adapter.EndRender(writer);

        }

        else

        {

             //如果没有,使用控件类本身的呈现方法呈现控件

            this.Render(writer);

        }

    }

    finally

    {

        this.EndRenderTracing(writer, this);

    }

}

⑤Render(HtmlTextWriter writer):

[TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]

protected internal virtual void Render(HtmlTextWriter writer)

{

    this.RenderChildren(writer);

}

⑥RenderChildren(HtmlTextWriter writer):

protected internal virtual void RenderChildren(HtmlTextWriter writer)

{

    ICollection controls = this._controls;

    this.RenderChildrenInternal(writer, controls);

}

⑦RenderChildrenInternal(HtmlTextWriter writer, ICollection children):

internal void RenderChildrenInternal(HtmlTextWriter writer, ICollection children)

{

    if (this.RareFields != null && this.RareFields.RenderMethod != null)

    {

        writer.BeginRender();

        this.RareFields.RenderMethod(writer, this);

        writer.EndRender();

        return;

    }

    if (children != null)     //如果子控件的集合不为空,继续递归;若为空,结束递归。

    {

        foreach (Control control in children)

        {

            control.RenderControl(writer);

        }

    }

}

2)控件树呈现的简单模型

上面我们分析了Control利用“合成模式”递归生成控件树的全过程,也注意到Control类用于呈现的6个方法中有三个是虚方法,它们是开发控件我们可重写改变呈现逻辑的部分。首先,我们用伪代码概述下Control类中这三个方法呈现控件的模型。

public virtual void RenderControl(HtmlTextWriter writer)

{

    if (this.Visible)

    {

        this.Render(writer);

    }

}

protected internal virtual void Render(HtmlTextWriter writer)

{

    --><div...

    this.RenderChildren(writer);

    --></div>

}

protected internal virtual void RenderChildren(HtmlTextWriter writer)

{

    if (this._controls != null) 

    {

        foreach (Control control in this._controls)

        {

            control.RenderControl(writer);

        }

    }

}

二、从Control类派生"相册"控件

1)“相册”控件初实现

通过上面的分析,很显然我们需要重写Render()方法的呈现逻辑,以输出我们期待呈现的内容。对,你一定还记得初始ASP.NET控件开发中的“HelloWorld”吧?

那你应该能写出这样的代码:

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Text;

using System.Web;

using System.Web.UI;

using System.Web.UI.WebControls;

namespace CustomServerControls

{

    public class Albumn : Control

    {

        protected override void Render(HtmlTextWriter writer)

        {

            writer.WriteLine(@"<div style=""text-align:center;width:194px;height:194px;background:url(Images/background.gif) no-repeat left"">");

            writer.WriteLine(@" <img src=""Images/Nature.jpg"" width=""160"" height=""160"" style=""border:none;padding:0px;margin-top:16px;"">");

            writer.WriteLine(@"</div>");

        }

    }

}

2)HtmlTextWriter的四个方法

上面,我们已经实现了一个很不完善的“相册”控,勉强实现了HTML代码的输出。但这样用字符串来组织输出内容我们不能利用IDE的智能感知功能,也不能在编码时捕获错误,更谈不上不同浏览器生成不同的HTML代码。哪应该怎样呢?其实,HtmlTextWriter类已经封装了很多生成HTML代码的方法。下面介绍四个最常用的:

①RenderBeginTag():生成HTML起始标签

public virtual void RenderBeginTag(HtmlTextWriterTag tagKey);

public virtual void RenderBeginTag(string tagName);

②RenderEndTag():生成HTML结束标签

public virtual void RenderEndTag();

AddAttribute():为HTML标签添加属性

public virtual void AddAttribute(string name, string value);

public virtual void AddAttribute(string name, string value, bool fEndode);

public virtual void AddAttribute(HtmlTextWriterAttribute key, string value);

public virtual void AddAttribute(HtmlTextWriterAttribute key, string value, bool fEncode);

AddStyleAttribute():为HTML标签添加样式属性

public virtual void AddStyleAttribute(string name, string value);

public virtual void AddStyleAttribute(HtmlTextWriterStyle key, string value)

  • 值得注意的是:当需要向一个标签添加属性和样式属性时,在调用生成HTML其实标签的RenderBeginTag()方法之前先调用AddAttribute()方法和AddStyleAttribute()方法添加所有必要的属性和样式属性。

3)“相册”控件再实现

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Text;

using System.Web;

using System.Web.UI;

using System.Web.UI.WebControls;

 

namespace CustomServerControls

{

    public class Albumn : Control

    {

        protected override void Render(HtmlTextWriter writer)

        {

            //最外层DIV的样式属性

            writer.AddStyleAttribute(HtmlTextWriterStyle.TextAlign, "center");

            writer.AddStyleAttribute(HtmlTextWriterStyle.Width, "194px");

            writer.AddStyleAttribute(HtmlTextWriterStyle.Height, "194px");

            writer.AddStyleAttribute("background", "url(Images/background.gif) no-repeat left");

 

            //最外层的Div开始

            writer.RenderBeginTag(HtmlTextWriterTag.Div);

 

 

            //IMG标签的属性和样式属性

            writer.AddAttribute(HtmlTextWriterAttribute.Src, "images/nature.jpg");

            writer.AddAttribute(HtmlTextWriterAttribute.Width, "160");

            writer.AddAttribute(HtmlTextWriterAttribute.Height, "160");

            writer.AddStyleAttribute(HtmlTextWriterStyle.BorderStyle, "none");

            writer.AddStyleAttribute(HtmlTextWriterStyle.Padding, "0px");

            writer.AddStyleAttribute(HtmlTextWriterStyle.MarginTop, "16px");

 

            //生成Img标签

            writer.RenderBeginTag(HtmlTextWriterTag.Img);

            writer.RenderEndTag();

 

            //最外层DIV结束

            writer.RenderEndTag();

        }

    }

}

第二篇:呈现内容_第一节:Control呈现的更多相关文章

  1. 第二篇:呈现内容_第二节:WebControl呈现

    一.WebControl的呈现过程 WebControl派生自Control类,所以WebControl的呈现功能基于Control的呈现逻辑之上,但有了比较大的扩展. 首先,WebControl重写 ...

  2. 机器学习_第一节_numpy

    今天学了机器学习第一节, 希望能够坚持下去,其实不在乎课程是什么?关键要坚持下去 今天主要学了对矩阵的一些操作, 用的库是numpy 开始从头到尾捋一遍, 作者说的很有道理,学计算机,动手能力要强,所 ...

  3. android内部培训视频_第一节

    声明:本视频为公司内部做android培训时录制的,无任何商业目的.同时鉴于水平有限,可能不符合您的需求,放在这里的目的是提供给公司同事下载,作为培训的一个记录,也作为一个系列教程的自我督促完成的理由 ...

  4. 第二篇:呈现内容_第三节:CompositeControl呈现

    一.CompositeControl的呈现过程 CompositeControl派生自WebControls,重写了Render(HtmlTextWriter writer)方法.在调用基类WebCo ...

  5. 第一篇:初识ASP.NET控件开发_第一节:控件类及其继承关系

    1)System.Web.UI.Control(以下简称Control) Control 类是包括自定义控件.用户控件和页在内的所有 ASP.NET 服务器控件的基类..定义由所有 ASP.NET 服 ...

  6. 第二篇 dom内容操作之value

    一.内容操作的三种方式 . 详情看第一篇 innerText innerHtml . value ==>表单类的标签 input >text passwd textarea . check ...

  7. Vue快速学习_第一节

    之前写CRM都是Django前后端一起写的,在大部分项目中实际上前后端是分离的,因此我们需要学习一个前端框架来进行前端页面的编写,这里选择了Vue进行学习,好了开始学习吧. 1.ES6部分知识点学习 ...

  8. 第二篇 Fiddler配置_浏览器&手机

    什么是Fiddler? 网络项目的开发和测试中,Fiddler是强大的抓包工具,它的原理是以web代理服务器的形式进行工作的 ,可以说是非常常用的手头工具了,本文就Fiddler使用和配置进行说明. ...

  9. 第二部分 实习操作课程 第一节 ArcGIS Online的基本功能

随机推荐

  1. python xlwt写excel格式控制 颜色、模式、编码、背景色

    关于写excel的格式控制,比如颜色等等 import xlwt from datetime import datetime font0 = xlwt.Font() font0.name = 'Tim ...

  2. Aerospike系列:7:数据分布详解

    1:Aerospike数据库是Shared-Nothing架构,集群中的每个节点都是相同的,不会出现单点故障. Aerospike有智能分区算法,即把用户输入的key在内部根据RIPEMD-160算法 ...

  3. 【Windows】XShell中使用小键盘和ALT键(作Meta键),使BackSpace正常

    小键盘: 打开终端的Session属性,VT模式,初始数字键盘模式,设置为普通 ALT键: 打开终端的Session属性,元(Meta)键仿真,将ALT用作Meta键 BackSpace: 打开终端的 ...

  4. Liability

    Liability li·a·bil·i·ty  ˌlīəˈbilədē/   noun A person or thing whose presence or behavior is likely ...

  5. Highcharts X轴纵向显示

    xAxis: { categories: ['苹果', '橘子', '梨', '葡萄', '香蕉'], labels:{ rotation: 90, style:{ fontSize: '13px', ...

  6. 分享一个VS2008漂亮的黑色主题

    如果恰巧你也使用Visual Studio 2008这个版本, 如果你也恰巧厌烦了白色的背景, 那么推荐你使用这款纯黑色theme,搭配上DroidSansMonog这个等宽字体(打包下载),每天都可 ...

  7. 如何通过Html网页调用本地安卓app?

    如何使用html网页和本地app进行传递数据呢?经过研究,发现还是有方法的,总结了一下,大致有一下几种方式 更新一下吧,这篇日志写于2013年11月,离现在已经很久了,依然很多朋友在查阅.目前应该有更 ...

  8. ios中键盘处理(二)

    设置UIscrollview的背景代码 - (UIImage *) ImageWithColor: (UIColor *) color frame:(CGRect)aFrame { UIGraphic ...

  9. 一个死去的网站shige.laiyo.com

    2017年4月份的时候,研一下刚刚开始. 爬了这个网站,现在这个网站已经关闭了,这些爬虫代码也就没用了,面向特定网站爬虫本身就是没有意义的. 爬author import requests from ...

  10. linux shell 脚本攻略学习1

    1.关于echo和printf打印输出 如果要使用转义序列,那么需要在echo 后面加上参数 -e来进行识别,下面例子是进行对比: amosli@amosli-pc:~/learn$ echo -e ...