主题,解析WebControl的呈现方法!
如果您还不了解Control的呈现过程,请点击这里http://www.cnblogs.com/wmj/archive/2008/03/17/1109072.html
先不讲WebControl呈现方法的细节问题,大家回想一下,在重写Control的Render方法的时候,整个控件的呈现逻辑全部在一个方法中实现,控件的元素,属性,样式属性混在一起,感觉特乱!有没有更好的设计方案呢?
能不能把呈现过程分一下层呢?比如说,把最外层元素单独放在某个方法呈现,并且她的属性和样式属性也在一个独立的方法中实现,再用一个独立的方法把控件的内容呈现出来,这样感觉是不是舒服多了?在我们想这些之前,其实MS早就替我们做好了一切,当然,MS的这种设计并不一定就是十全十美的!
按照上面的思路,并对照WebControl的方法进行讲解!
一,用来呈现控件最外层元素的方法或者属性是怎样定义的呢?
TagKey属性专门定义最外层的元素
图一
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), Browsable(false)]
protected virtual HtmlTextWriterTag TagKey


{
get

{
return this.tagKey;
}
}

当TagKey的“value==null”的时候,TagName派上用场了,这时我们就可以自定义一些系统没有的元素了,注意她是字符串类型!
图二
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), Browsable(false)]
protected virtual string TagName


{
get

{
if ((this.tagName == null) && (this.TagKey != HtmlTextWriterTag.Unknown))

{
this.tagName = Enum.Format(typeof(HtmlTextWriterTag), this.TagKey, "G").ToLower(CultureInfo.InvariantCulture);
}
return this.tagName;
}
}
那么最外层元素的属性和样式是怎样定义的呢?当然是AddAttributesToRender方法了,由于此方法的内部实现比较复杂,在此就不列出来了!只要明白一点,她是为最外层元素服务的!并且在先于RenderContents方法调用!还记得我们在重写Control的时候,先定义控件的属性和样式,然后才定义控件的元素,记得否?我还是贴一张图吧,有时候我也这样健忘J
图三
writer.AddStyleAttribute(HtmlTextWriterStyle.BorderWidth, "0");
writer.RenderBeginTag(HtmlTextWriterTag.Table);
writer.RenderBeginTag(HtmlTextWriterTag.Tr);
writer.RenderBeginTag(HtmlTextWriterTag.Td);
//…

二,WebControl用来呈现内容的方法是怎样定义的呢?
首先重写了Control的Render方法
图四
protected internal override void Render(HtmlTextWriter writer)


{
this.RenderBeginTag(writer);
this.RenderContents(writer);
this.RenderEndTag(writer);
}
先看RenderContents方法,啥也没干,就调用基类的virtual Render方法!
图五
protected internal virtual void RenderContents(HtmlTextWriter writer)


{
base.Render(writer);
}



再看看RenderBeginTag和RenderEndTag方法,有点意思哦!
图六
public virtual void RenderBeginTag(HtmlTextWriter writer)


{
this.AddAttributesToRender(writer);
HtmlTextWriterTag tagKey = this.TagKey;
if (tagKey != HtmlTextWriterTag.Unknown)

{
writer.RenderBeginTag(tagKey);
}
else

{
writer.RenderBeginTag(this.TagName);
}
}
图七
public virtual void RenderEndTag(HtmlTextWriter writer)


{
writer.RenderEndTag();
}
看到了吗?所有的最外层的元素,属性,和样式都在此做完了!(没错,我前面说过AddAttributesToRender方法在RenderContents之前被调用!),还要注意一点的就是
writer.RenderBeginTag(tagKey)和writer.RenderEndTag()方法都是HtmlTextWriter对象的方法,而非WebControl本身的方法!
虽然,这种“记流水帐形式”的文风,有点“那个”,但只要能说清楚问题,也就懒得在意了J
还是举个例子吧,免得有人说我懒(我妈说我懒)!
下面的demo呈现一个Lable,重写最外层元素span为Div,背景色为红色,并在Lable的内容中加一个背景色为蓝色的Div,就这么简单!
图八
using System;
using System.Web.UI;
using System.ComponentModel;
using System.Web.UI.WebControls;

namespace ClassLibrary1


{
[DefaultPropertyAttribute("Text")]
[ToolboxData(@"<{0}:WMJLable Text='哈哈' name='小声的笑' runat='server'></{0}:WMJLable>")]

public class WMJLable:WebControl

{
//字段
string _text = string.Empty;
string _name = string.Empty;
//属性
public string Text

{
get

{
if (ViewState["Text"] == null)
return "";
else
return ViewState["Text"].ToString();
}
set

{
ViewState["Text"] = value;
}
}
public string Name

{
get

{
if (ViewState["Name"] == null)
return "";
else
return ViewState["Name"].ToString();
}
set

{
ViewState["Name"] = value;
}
}
//重写最外层标签,默认为SPAN
protected override HtmlTextWriterTag TagKey

{

get
{ return HtmlTextWriterTag.Div; }
}

//重写最外层标签Div的样式属性,把边框色弄成红色
protected override void AddAttributesToRender(HtmlTextWriter writer)

{
base.AddAttributesToRender(writer);
writer.AddStyleAttribute(HtmlTextWriterStyle.BackgroundColor, "Red");
writer.AddStyleAttribute(HtmlTextWriterStyle.Width, "400px");
}

protected override void RenderContents(HtmlTextWriter writer)

{
base.RenderContents(writer);

writer.Write(Text);
writer.AddStyleAttribute(HtmlTextWriterStyle.BackgroundColor, "Blue");
writer.AddStyleAttribute(HtmlTextWriterStyle.Width, "300px");
writer.AddAttribute(HtmlTextWriterAttribute.Name, Name);
writer.RenderBeginTag(HtmlTextWriterTag.Div);
writer.RenderEndTag() ;
}
}
}

效果图

参考
Clingingboy