zoukankan      html  css  js  c++  java
  • 第二篇:呈现内容_第一节:Control呈现

    一、Control的呈现过程

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

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

    clipboard

    控件树的呈现过程是一个华丽的大圈,它从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;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();
            }
        }
    }
  • 相关阅读:
    (简单) POJ 1860 Currency Exchange,SPFA判圈。
    (简单) POJ 3259 Wormholes,SPFA判断负环。
    (简单) POJ 1502 MPI Maelstrom,Dijkstra。
    (中等) POJ 3660 Cow Contest,Floyd。
    (简单) POJ 2240 Arbitrage,SPFA。
    3.Git基础-查看当前文件状态、跟踪新文件、暂存文件、忽略文件、提交更新、移除文件、移动文件
    2.Git基础-仓库的获取方式与Git文件的状态变化周期(生命周期)
    1.Git起步-Git的三种状态以及三种工作区域、CVCS与DVCS的区别、Git基本工作流程
    获取URL参数
    进度条
  • 原文地址:https://www.cnblogs.com/hanzhaoxin/p/4052584.html
Copyright © 2011-2022 走看看