3.3
System.Web.UI.WebControls.Style类介绍
该类是一个样式类,这个类可对由WebControl类继承的控件添加了样式属性,具体的做法我们在下面会介绍的。当然
我们也可以创建继承自该类的自定义样式类,为我们的控件添加更加多的样式特性。下面我们开始介绍Style类中的方法和属
性,最后我们会结合实例来说明自定义样式类的使用方法。
3.3.1 CopyFrom方法和MergeWith方法
这两个方法我们在讲WebControl类的ApplyStyle和MergeStyle方法时已经有所提到。一般当我们创建自定义样式类的
时候都会重写这2个方法,将我们自定义的样式特性添加到自定义样式类中。当我们重写这两个方法时要记住调用父类Style
中的这两个方法。
3.3.2 AddAttributesToRender方法
该方法是我们创建自定义样式类是比较重要的方法,我们一般会重写该方法将自定义样式特性添加到输出流。当然当我们
重写该方法时务必调用基类中的该方法。
这里我们先来看下Style类的构造函数代码:
//该构造函数一般在我们重写继承自WebControl类的控件的CreateControlStyle方法时使用
public Style(StateBag bag)
{
//设置statebag为传入的StateBag类对象,一般为我们定义的控件的ViewState属性。
this.statebag = bag;
this.marked = false;
this.setBits = 0;
}
下面我们来看下Style类中该方法的部分代码:
public virtual void AddAttributesToRender(HtmlTextWriter writer, WebControl owner)
{
Color color1;
Unit unit1;
//将ViewState属性传给bag1,其实也就时将构造函数中设置的statebag成员传给bag1
StateBag bag1 = this.ViewState;
if (this.IsSet(2))
{
//得到定义的CssClass特性值
string text1 = (string) bag1["CssClass"];
if (text1.Length > 0)
{
//为输出流添加Class样式特性和值
writer.AddAttribute(HtmlTextWriterAttribute.Class, text1);
}
}
if (this.IsSet(4))
{
color1 = (Color) bag1["ForeColor"];
if (!color1.IsEmpty)
{
writer.AddStyleAttribute(HtmlTextWriterStyle.Color, ColorTranslator.ToHtml(color1));
}
}
……
……
……
}
看了这些代码应该知道如何使用该方法和重写该方法了吧!该方法有2个参数,第一个参数是我们指定的要将样式特性输出到
的HtmlTextWrite输出流,第2个参数是要使用样式的控件,一般为我们定义的控件或其子控件。
3.3.3 Style类的属性
ViewState属性,该属性是只读的,只能被继承访问。如何设置该属性的呢?我们可以调用该类的构造函数指定私有成
员statebag的对象来设置该属性,当我们读取该属性时读取的就是私有成员statebag。该属性在我们调用或重写
AddAttributesToRender方法时要用到,在自定义的样式类属性里也要用到。看下该属性的代码:
protected internal StateBag ViewState
{
get
{
if (this.statebag == null)
{
//当statebag为空时时将为statebag成员创建新对象
this.statebag = new StateBag(false);
if (this.IsTrackingViewState)
{
this.statebag.TrackViewState();
}
}
return this.statebag;
}
}
由于该属性的访问权限为protected internal,所以在使用时如何使用大家要注意。
IsEmpty属性,该属性在我们自定义样式类中比较重要,因为该属性访问权限为protected internal所以我们
能在派生类中使用该属性,该属性是虚属性所以我们可以重写该属性,用于判断样式类是否有定义样式,该属性在
WebControl类的ApplyStyle和MergeStyle方法中被用到。具体看下面的例子。
Style类中的其他属性还有BackColor,BorderStyle等分别与WebControl类中的样式属性对应。当然我们可以
为自定义的样式类创建更多的样式属性对应于HTML标记符中的样式特性。
3.3.4 自定义样式类及其使用实例
本节我们将创建一个表格控件,为HTML表格添加cellpadding,cellspacing,border和background样式特性。
下面我们就来看看示例(例3-6)
例3-6:
using
System;
using
System.Web.UI;
using
System.Web.UI.WebControls;
using
System.ComponentModel;
namespace
style_table_3_6
{
//这里我们首先定义一个继承自Style的样式类
public class AspTableStyle:Style
{
private bool isempty; //该变量用于判断自定义样式是否被设置
public AspTableStyle()
{
isempty=true; //设置样式没被定义
}
public AspTableStyle(StateBag bag) : base(bag) //构造函数调用基类的构造函数
{
isempty=true;
}
public virtual int CellPadding //该属性指定表格的单元格边距
{
get
{
if (base.ViewState["CellPadding"]!=null)
{
return (int) base.ViewState["CellPadding"];
}
return 0;
}
set
{
if (value < -1) //当值不在范围内将抛出异常
{
throw new ArgumentOutOfRangeException("value");
}
base.ViewState["CellPadding"] = value;
isempty=false; //设置样式已被定义
}
}
public virtual int CellSpacing //该属性指定表格的单元格间距
{
get
{
if (base.ViewState["CellSpacing"]!=null)
{
return (int) base.ViewState["CellSpacing"];
}
return 0;
}
set
{
if (value < -1)
{
throw new ArgumentOutOfRangeException("value");
}
base.ViewState["CellSpacing"] = value;
isempty=false;
}
}
public virtual int Border //该属性指定表格的边框粗细
{
get
{
if (base.ViewState["Border"]!=null)
{
return (int) base.ViewState["Border"];
}
return 0;
}
set
{
if (value < -1)
{
throw new ArgumentOutOfRangeException("value");
}
base.ViewState["Border"] = value;
isempty=false;
}
}
public virtual string BackGround //指定表格的背景图片地址
{
get
{
if (base.ViewState["BackGround"]!=null)
{
return (string) base.ViewState["BackGround"];
}
return string.Empty;
}
set
{
if (value == null)
{
throw new ArgumentNullException("value");
}
base.ViewState["BackGround"] = value;
isempty=false;
}
}
protected override bool IsEmpty //该属性用于判断样式属性是否被设置
{
get
{
if(isempty==false)
{
return false;
}
//当我们自定义的样式没被设置时返回基类的属性,判断基类中是否有属性被设置
return base.IsEmpty;
}
}
public override void AddAttributesToRender(HtmlTextWriter writer, WebControl owner)
{
base.AddAttributesToRender (writer, owner);
string text1 = this.BackGround;
if (text1.Length != 0)
{
writer.AddStyleAttribute(HtmlTextWriterStyle.BackgroundImage, "url(" + text1 + ")"); //指定背景图片
}
int num1 = this.CellSpacing;
if (num1 >= 0)
{
writer.AddAttribute(HtmlTextWriterAttribute.Cellspacing, num1.ToString());
if (num1 == 0)
{
writer.AddStyleAttribute(HtmlTextWriterStyle.BorderCollapse, "collapse");
}
}
num1 = this.CellPadding;
if (num1 >= 0)
{
writer.AddAttribute(HtmlTextWriterAttribute.Cellpadding, num1.ToString());
}
num1 = this.Border;
if (num1 >= 0)
{
writer.AddAttribute(HtmlTextWriterAttribute.Border, num1.ToString());
}
}
public override void CopyFrom(Style s) //这里重写了基类的方法
{
if ((s != null))
{
base.CopyFrom(s);
if (s is AspTableStyle)
{
AspTableStyle style1 = (AspTableStyle) s;
if (style1.BackGround!=null)
{
this.BackGround = style1.BackGround;
}
this.CellPadding = style1.CellPadding;
this.CellSpacing = style1.CellSpacing;
this.Border=style1.Border;
}
}
}
public override void MergeWith(Style s)
{
if ((s != null))
{
if (this.IsEmpty)
{
this.CopyFrom(s);
}
else
{
base.MergeWith(s);
if (s is AspTableStyle)
{
AspTableStyle style1 = (AspTableStyle) s;
if (style1.BackGround==null)
{
this.BackGround = style1.BackGround;
}
if (style1.CellPadding==0)
{
this.CellPadding = style1.CellPadding;
}
if (style1.CellSpacing==0)
{
this.CellSpacing = style1.CellSpacing;
}
if (style1.Border==0)
{
this.Border= style1.Border;
}
}
}
}
}
public override void Reset()
{
if (this.BackGround!=null)
{
base.ViewState.Remove("BackImageUrl");
}
if (this.CellPadding!=0)
{
base.ViewState.Remove("CellPadding");
}
if (this.CellSpacing!=0)
{
base.ViewState.Remove("CellSpacing");
}
base.Reset();
}
}
[DefaultProperty("Text"),
ToolboxData("<{0}:WebCustomControl1 runat=server></{0}:WebCustomControl1>")]
public class WebCustomControl1 : System.Web.UI.WebControls.WebControl
{
public WebCustomControl1():base(HtmlTextWriterTag.Table)
{
}
public virtual int CellPadding //设置控件本身的样式属性
{
get
{
if (!base.ControlStyleCreated)
{
return -1;
}
return ((AspTableStyle) base.ControlStyle).CellPadding;
}
set
{
((AspTableStyle) base.ControlStyle).CellPadding = value;
}
}
public virtual int CellSpacing
{
get
{
if (!base.ControlStyleCreated)
{
return -1;
}
return ((AspTableStyle) base.ControlStyle).CellSpacing;
}
set
{
((AspTableStyle) base.ControlStyle).CellSpacing = value;
}
}
public virtual int Border
{
get
{
if (!base.ControlStyleCreated)
{
return -1;
}
return ((AspTableStyle) base.ControlStyle).Border;
}
set
{
((AspTableStyle) base.ControlStyle).Border= value;
}
}
public virtual string BackGround
{
get
{
if (!base.ControlStyleCreated)
{
return string.Empty;
}
return ((AspTableStyle) base.ControlStyle).BackGround;
}
set
{
((AspTableStyle) base.ControlStyle).BackGround = value;
}
}
protected override Style CreateControlStyle() //重写基类方法创建自定义样式的实例
{
return new AspTableStyle(this.ViewState); //返回自定义样式的实例
}
protected override void RenderContents(HtmlTextWriter writer)
{
int num1=this.Controls.Count; //得到控件的子控件数
int num2=0;
int num3=0;
if(num1%4!=0)
{
num2=(num1/4)+1;
}
else
{
num2=num1/4;
}
if(num1!=0)
{
for(int num5=1;num5<=num2;num5++)
{
writer.RenderBeginTag(HtmlTextWriterTag.Tr);
for(int num6=1;num6<=4;num6++)
{
writer.RenderBeginTag(HtmlTextWriterTag.Td);
if(num3<num1)
{
this.Controls[num3].RenderControl(writer); //显示单个子控件
}
else
{
writer.Write("null");
}
num3++;
writer.RenderEndTag();
}
writer.RenderEndTag();
}
}
else
{
writer.RenderBeginTag(HtmlTextWriterTag.Tr);
writer.RenderBeginTag(HtmlTextWriterTag.Td);
writer.Write("没有任何子控件");
writer.RenderEndTag();
writer.RenderEndTag();
}
}
}
}
代码确实比较长,但用到了我们前面提到的很多知识,请大家务必认真看下,当然如果你了解该方面的知识是不
用看了,因为这比较的基础。如果大家想运行下该控件可以下载该控件的源代码。
下面我们来看看如何使用该控件,我们先将该控件加入自己的页面然后可以修改后置代码(.cs文件)的
InitializeComponent方法如下:
private void InitializeComponent()
{
Button bt1=new Button(); //新建一个Button控件
bt1.Text="Button1";
Button bt2=new Button();
bt2.Text="Button2";
Button bt3=new Button();
bt3.Text="Button3";
Button bt4=new Button();
bt4.Text="Button4";
Button bt5=new Button();
bt5.Text="Button5";
Button bt6=new Button();
bt6.Text="Button6";
//定义一个自定义的样式对象
style_table_3_6.AspTableStyle ats=new style_table_3_6.AspTableStyle();
ats.CellPadding=9; //设置样式属性
ats.CellSpacing=9;
ats.BorderColor=Color.Blue;
WebCustomControl11.ApplyStyle(ats); //用自定义样式覆盖控件样式
WebCustomControl11.Border=3; //定义控件本身的样式属性
WebCustomControl11.Controls.Add(bt1); //添加子控件
WebCustomControl11.Controls.Add(bt2);
WebCustomControl11.Controls.Add(bt3);
WebCustomControl11.Controls.Add(bt4);
WebCustomControl11.Controls.Add(bt5);
WebCustomControl11.Controls.Add(bt6);
}
为方便我将Button控件的创建都定义在该方法里了。
下面看看运行结果吧(图3-9)
图
3-9

在上面的例子中我们首先定义了一个样式类AspTableStyle,重写了几个基类的方法,这几个方法我们在上面已经介绍过了,具体的用法大家还要从代码中认真揣摩下。我们也重写了IsEmpty属性,我个人认为重写IsEmpty属性是判断自定义的样式属性是否被设置最简单的做法。
在上面这个例子的最后我们还使用了
RenderControl方法来显示子控件,关于该方法我们在上面没有提到,其实该方法是在Control类中定义的,RenderChildren方法中用到了该方法来显示控件的每一个子控件,关于该方法的用法就如上面的例子所示。
关于样式类的使用及如何创建自定义样式类我们就讲到这里为止了,下面我们会对控件开发相关的接口进行下介绍。