上一篇讲了关于属性方面的一些东西 ,这次讲的是关于样式.

位于WebControls命名空间的style类为顶级样式类.大部分标准控件都拥有其样式属性.

1.下面为设置样式方法

(1)你可以直接设置控件样式
None.gifButton1.BackColor = System.Drawing.Color.Red;

(2)通过获取web控件的样式集合来设置

None.gifButton1.ControlStyle.BackColor = System.Drawing.Color.Red;

(3)通过设置样式类,利用WebControl类的ApplyStyle方法来复制非空样式,并改写现有样式

None.gif        myStyle.BackColor = System.Drawing.Color.Red;
None.gif        Button1.ApplyStyle(myStyle);

(4)一直定义样式表属性,不使用控件属性,与定义HTML样式相同.

None.gif style="background-color: red"


下面引出话题,为什么要使用样式?大家知道定义样式可以使用统一风格,定义好的样式,可以重复使用.再回来看上面设置样式方法.

2.了解WebControl.BackColor和Style.BackColor

(1)和(2)是差不多的.但(3)则不同,(3)的定义方法有通用性,你可以定义一种样式,然后利用控件的ApplyStyle方法来引用样式.给样式编程提供了方面

WebControl类定义了通用的样式.(1)和(2)使用的样式属性为

None.gifWebControl.BackColor

(3)则不同,使用的为

None.gifStyle.BackColor

3.自定义样式属性

刚开始就讲了style类为通用的顶级样式类,但需求是会发生变化的. 好了,下面真正开始编码了.
下面以改写label控件为例子

(1)改写样式属性,让其默认背景为红色,相信大家一定看的懂

示例一
None.gifnamespace CustomComponents
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif    [ToolboxData(
@"<{0}:ImageLabel1 
InBlock.gif    BackColor='Red'
InBlock.gif    runat='server'></{0}:ImageLabel1>
")
InBlock.gif    ]
InBlock.gif    
public class ImageLabel1 : Label
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        
public override string Text
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif            
get dot.gifreturn ViewState["Text"!= null ? (string)ViewState["Text"] : base.ID; }
ExpandedSubBlockStart.gifContractedSubBlock.gif            
set dot.gif{ ViewState["Text"= value; }
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
public override System.Drawing.Color BackColor
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
get
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                
return base.BackColor = System.Drawing.Color.Red;
ExpandedSubBlockEnd.gif            }

InBlock.gif            
set
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                
base.BackColor = value;
ExpandedSubBlockEnd.gif            }

ExpandedSubBlockEnd.gif        }

ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}

控件初始效果为下图


(2)为label新增一个背景图片的属性,重写了一下AddAttributesToRender方法,添加一个样式属性,AddAttributesToRender方法以前为大家讲过,这里不多讲了.

示例二
None.gifnamespace CustomComponents
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif    
public class ImageLabel2 : Label
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        [BrowsableAttribute(
true)]
InBlock.gif        [DescriptionAttribute(
"背景")]
InBlock.gif        [CategoryAttribute(
"Appearance")]
InBlock.gif        
public virtual String ImageUrl
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif            
get dot.gifreturn ViewState["imageUrl"!= null ? (string)ViewState["imageUrl"] : ""; }
ExpandedSubBlockStart.gifContractedSubBlock.gif            
set dot.gif{ ViewState["imageUrl"= value; }
ExpandedSubBlockEnd.gif        }

InBlock.gif        
override protected void AddAttributesToRender(HtmlTextWriter writer)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            writer.AddStyleAttribute(HtmlTextWriterStyle.BackgroundImage, ImageUrl);
InBlock.gif            
base.AddAttributesToRender(writer);
ExpandedSubBlockEnd.gif        }

ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}

使用控件效果如下



(3)上面示例二中我们定义了背景样式,其实.net已经为我们把工作做好了

从style类派生了很多样式类,扩展了style类的属性,满足不同控件样式的需求.

WebControl类中有一个CreateControlStyle 方法,其返回为一个样式集合.其默认情况下实现如下

None.gif        protected override Style CreateControlStyle()
ExpandedBlockStart.gifContractedBlock.gif        
dot.gif{
InBlock.gif            
return new Style(ViewState);
ExpandedBlockEnd.gif        }

我们可以通过改写此方法来使控件拥有style派生类的功能,改写后如下,让label控件拥有TableStyle类的样式

None.gif        protected override Style CreateControlStyle()
ExpandedBlockStart.gifContractedBlock.gif        
dot.gif{
InBlock.gif            
return new TableStyle(ViewState);
ExpandedBlockEnd.gif        }


注意点:默认情况下,当label控件使用ApplyStyle复制除style之外的样式属性集合,将只返回默认style类的样式属性集合.

看了下面效果后请再回头再理解这句话.

看下面自定义控件代码,真是简单的不的了

示例三
None.gifnamespace CustomComponents
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif    
public class ImageLabel3 : Label
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif
InBlock.gif        
protected override Style CreateControlStyle()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
return new TableStyle(ViewState);
ExpandedSubBlockEnd.gif        }

ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}


再看默认label控件与其的对比,因为没有给控件定义样式属性,所以只能通过编程的方式来定义样式,如下

示例四
None.gif    protected void Page_Load(object sender, EventArgs e)
ExpandedBlockStart.gifContractedBlock.gif    
dot.gif{
InBlock.gif        
//默认label控件
InBlock.gif
        TableStyle a = new TableStyle();
InBlock.gif        a.BackImageUrl 
= "images4.bmp";
InBlock.gif        a.BackColor 
= System.Drawing.Color.Red;
InBlock.gif        Label1.ApplyStyle(a);
InBlock.gif        
//自定义控件
InBlock.gif
        ImageLabel3_1.ApplyStyle(a);
ExpandedBlockEnd.gif    }

看一下,使用的效果,看到下面效果再来理解下我上面说的注意点吧.我想这样会理解的更深刻.




(4)使用派生样式类,定义控件样式属性.示例四中说过了,没有定义控件样式属性,只改写了CreateControlStyle方法.那就意味了你定义的控件样式属性可以直接使用TableStyle类中的属性,但默认情况下的样式属性为style类中属性,所以需要强行转换.如下对比

默认情况下

None.gif        public override Color BackColor
ExpandedBlockStart.gifContractedBlock.gif        
dot.gif{
InBlock.gif            
get
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                
return ((Style)ControlStyle).BackColor;
ExpandedSubBlockEnd.gif            }

InBlock.gif            
set
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                ((Style)ControlStyle).BackColor 
= value;
ExpandedSubBlockEnd.gif            }

ExpandedBlockEnd.gif        }


定义TableStyle样式属性,必须转换为TableStyle类型

None.gif        public virtual string BackImageUrl
ExpandedBlockStart.gifContractedBlock.gif        
dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif            
get dot.gifreturn ((TableStyle)ControlStyle).BackImageUrl; }
ExpandedSubBlockStart.gifContractedSubBlock.gif            
set dot.gif{ ((TableStyle)ControlStyle).BackImageUrl = value; }
ExpandedBlockEnd.gif        }

好了,讲清楚上面这一点.我们再来测试一下.看下面示例(还是采用我们第一讲的例子)

下面只给出定义样式属性的代码,其他的类似.

ContractedBlock.gifExpandedBlockStart.gif
ContractedBlock.gifExpandedBlockStart.gif       控件样式#region 控件样式
InBlock.gif
InBlock.gif        
protected override Style CreateControlStyle()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif
InBlock.gif            
return new TableStyle(ViewState);
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        [BrowsableAttribute(
true)]
InBlock.gif        [DescriptionAttribute(
"网格线")]
InBlock.gif        [CategoryAttribute(
"Appearance")]
InBlock.gif        
public virtual GridLines GridLines
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif            
get dot.gifreturn ((TableStyle)ControlStyle).GridLines; }
ExpandedSubBlockStart.gifContractedSubBlock.gif            
set dot.gif{ ((TableStyle)ControlStyle).GridLines = value; }
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        [BrowsableAttribute(
true)]
InBlock.gif        [DescriptionAttribute(
"单元格间距")]
InBlock.gif        [CategoryAttribute(
"Appearance")]
InBlock.gif        
public virtual int CellSpacing
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif            
get dot.gifreturn ((TableStyle)ControlStyle).CellSpacing; }
ExpandedSubBlockStart.gifContractedSubBlock.gif            
set dot.gif{ ((TableStyle)ControlStyle).CellSpacing = value; }
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        [BrowsableAttribute(
true)]
InBlock.gif        [DescriptionAttribute(
"单元格边距")]
InBlock.gif        [CategoryAttribute(
"Appearance")]
InBlock.gif        
public virtual int CellPadding
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif            
get dot.gifreturn ((TableStyle)ControlStyle).CellPadding; }
ExpandedSubBlockStart.gifContractedSubBlock.gif            
set dot.gif{ ((TableStyle)ControlStyle).CellPadding = value; }
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        [BrowsableAttribute(
true)]
InBlock.gif        [DescriptionAttribute(
"表水平对齐")]
InBlock.gif        [CategoryAttribute(
"Appearance")]
InBlock.gif        
public virtual HorizontalAlign HorizontalAlign
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif            
get dot.gifreturn ((TableStyle)ControlStyle).HorizontalAlign; }
ExpandedSubBlockStart.gifContractedSubBlock.gif            
set dot.gif{ ((TableStyle)ControlStyle).HorizontalAlign = value; }
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        [BrowsableAttribute(
true)]
InBlock.gif        [DescriptionAttribute(
"表背景图片")]
InBlock.gif        [CategoryAttribute(
"Appearance")]
InBlock.gif        
public virtual string BackImageUrl
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif            
get dot.gifreturn ((TableStyle)ControlStyle).BackImageUrl; }
ExpandedSubBlockStart.gifContractedSubBlock.gif            
set dot.gif{ ((TableStyle)ControlStyle).BackImageUrl = value; }
ExpandedSubBlockEnd.gif        }

InBlock.gif
ExpandedBlockEnd.gif        
#endregion


使用此控件
None.gif    <custom:CreditCardForm6 BackColor="Black" ForeColor="White" runat="server" ID="example"
None.gif      Font-Bold
="true" Font-Italic="true" GridLines="None" CellSpacing="5" 
None.gif      BackImageUrl
="images4.bmp" Font-Size="Larger"
None.gif      BorderColor
="Yellow" BorderWidth="20px" BorderStyle="Ridge" HorizontalAlign="NotSet" EnableViewState="False" />

效果如下




好了,上面的基础讲完了.希望大家能够有所理解.下面还我们要讲一个重点的东西.

4.自定义类型化样式属性

如果样式属性无法满足你需求,则你可以通过自定义类型化样式来实现.
什么是自定义类型化样式?就是该类从style类派生,对其进行修改和扩充(书上就这么写了...我就这么理解了-_-)

如Table控件,一方面控件自身定义的样式属性,另一方面又定义了TableStyle类.你可以在使用控件样式属性和TableStyle类中进行选择.

但TableStyle类具有通用性,具有一定的灵活性.好了下面我们又要开始看代码了.当然从简单开始

(1)简单呈现样式属性

需要说明的注意点如下

1.重写LabelStyle(StateBag viewState)构造函数
2.样式属性需用视图状态来声明
3.Style类的重载的AddAttributesToRender方法需用两个参数的方法
AddAttributesToRender(HtmlTextWriter writer, WebControl owner)

示例5  自定义类型化样式:LabelStyle类 
None.gif    public class LabelStyle :Style
ExpandedBlockStart.gifContractedBlock.gif    
dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif        
public LabelStyle() dot.gif{ }
ExpandedSubBlockStart.gifContractedSubBlock.gif        
public LabelStyle(StateBag viewState) : base(viewState) dot.gif{ }
InBlock.gif
InBlock.gif        
public virtual String ImageUrl
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif            
get dot.gifreturn ViewState["imageUrl"!= null ? (string)ViewState["imageUrl"] : ""; }
ExpandedSubBlockStart.gifContractedSubBlock.gif            
set dot.gif{ ViewState["imageUrl"= value; }
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
public override void AddAttributesToRender(HtmlTextWriter writer, WebControl owner)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            writer.AddStyleAttribute(HtmlTextWriterStyle.BackgroundImage, ImageUrl);
InBlock.gif
InBlock.gif            
InBlock.gif            
base.AddAttributesToRender(writer, owner);
ExpandedSubBlockEnd.gif        }

ExpandedBlockEnd.gif    }

下面再来看控件实现方法,注意此处CreateControlStyle方法返回为自己定义的LabelStyle(ViewState)

示例6
None.gif    public class ImageLabel4 : Label
ExpandedBlockStart.gifContractedBlock.gif    
dot.gif{
InBlock.gif        
protected override Style CreateControlStyle()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
return new LabelStyle(ViewState);
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        [Bindable(
true),
InBlock.gif        Category(
"Appearance"),
InBlock.gif        DefaultValue(
""),
InBlock.gif        Description(
"背景图片")
InBlock.gif        ] 
InBlock.gif        
public virtual String ImageUrl
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif            
get dot.gifreturn ((LabelStyle)ControlStyle).ImageUrl; }
ExpandedSubBlockStart.gifContractedSubBlock.gif            
set dot.gif{ ((LabelStyle)ControlStyle).ImageUrl = value; }
ExpandedSubBlockEnd.gif        }

ExpandedBlockEnd.gif    }


让我们来测试一下,你会发现界面上并未呈现背景图片,给控件加一个属性CssClass=""以后效果就出来了,如下



让我们来思考为什么在未定义CssClass=""属性时无法呈现自定义属性.

Style类有一个IsEmpty属性用来判断已在的视图状态中是否定义了样式属性,
默认情况下为true,当定义了样式属性后,则为false.CssClass属性为空时,默认情况下即认为定义了样式属性,只不过样式属性个数为0.

若要在默认情况下呈现自定义样式属性则需重写IsEmpty属性.如下,只要判断自定义的样式属性视图状态是否为空即可.

示例7
None.gif        //判断视图状态是否为空
None.gif
        internal bool IsSet(string key)
ExpandedBlockStart.gifContractedBlock.gif        
dot.gif{
InBlock.gif            
return ViewState[key] != null;
ExpandedBlockEnd.gif        }

None.gif
ExpandedBlockStart.gifContractedBlock.gif        
/**//// <summary>
InBlock.gif        
/// 是否定义样式元素
ExpandedBlockEnd.gif        
/// </summary>

None.gif        public override bool IsEmpty
ExpandedBlockStart.gifContractedBlock.gif        
dot.gif{
InBlock.gif            
get
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                
return base.IsEmpty && !IsSet("imageUrl");
ExpandedSubBlockEnd.gif            }

ExpandedBlockEnd.gif        }


(2)使用编程

下面我们以编程方式,给控件添加自定义样式属性.
发现BackColor属性能够呈现但ImageUrl 无法呈现,那说明我们刚才自定义的类就失去意义了,也说明我们还未重写某个方法.
None.gif   LabelStyle a = new LabelStyle();
None.gif        a.ImageUrl 
= "images4.bmp";
None.gif        a.BackColor 
= System.Drawing.Color.Red;
None.gif        ImageLabel4_1.ApplyStyle(a);


Style类有三个操作样式的方法,复制,合并和清除样式.WebControl类也一样.重写一下,我们的目的就达到了.看下面代码

示例8
ContractedBlock.gifExpandedBlockStart.gif
ContractedBlock.gifExpandedBlockStart.gif方法#region 方法
InBlock.gif
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
InBlock.gif        
///  复制样式
InBlock.gif        
/// </summary>
ExpandedSubBlockEnd.gif        
/// <param name=""></param>

InBlock.gif        public override void CopyFrom(Style s)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
if (s == null)
InBlock.gif                
return;
InBlock.gif
InBlock.gif            
base.CopyFrom(s);
InBlock.gif            LabelStyle ls 
= s as LabelStyle;
InBlock.gif            
if (ls == null || ls.IsEmpty)
InBlock.gif                
return;
InBlock.gif
InBlock.gif            
if (ls.IsSet("imageUrl"))
InBlock.gif                
this.ImageUrl = ls.ImageUrl;
ExpandedSubBlockEnd.gif        }

InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
InBlock.gif        
/// 整合样式
InBlock.gif        
/// </summary>
ExpandedSubBlockEnd.gif        
/// <param name="s"></param>

InBlock.gif        public override void MergeWith(Style s)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
if (s == null)
InBlock.gif                
return;
InBlock.gif
InBlock.gif            
if (IsEmpty)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                CopyFrom(s);
InBlock.gif                
return;
ExpandedSubBlockEnd.gif            }

InBlock.gif
InBlock.gif            LabelStyle ls 
= s as LabelStyle;
InBlock.gif            
if (ls == null || ls.IsEmpty)
InBlock.gif                
return;
InBlock.gif
InBlock.gif            
if (ls.IsSet("imageUrl"&& !IsSet("imageUrl"))
InBlock.gif                
this.ImageUrl = ls.ImageUrl;
ExpandedSubBlockEnd.gif        }

InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
InBlock.gif        
/// 清除样式
ExpandedSubBlockEnd.gif        
/// </summary>

InBlock.gif        public override void Reset()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
base.Reset();
InBlock.gif            
if (IsEmpty)
InBlock.gif                
return;
InBlock.gif
InBlock.gif            
if (IsSet("imageUrl"))
InBlock.gif                ViewState.Remove(
"imageUrl");
ExpandedSubBlockEnd.gif        }

ExpandedBlockEnd.gif        
#endregion


好了,再次编译测试一下,效果也出来了.

这里再写一点.再呈现的时候可以重写另一个方法来代替AddAttributesToRender方法,如下

None.gifprotected override void FillStyleAttributes(CssStyleCollection attributes, IUrlResolutionService urlResolver)
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif    
base.FillStyleAttributes(attributes, urlResolver);
InBlock.gif    attributes.Add(HtmlTextWriterStyle.BackgroundImage, ImageUrl);
ExpandedBlockEnd.gif}


关于对样式的理解基本的东西就先写这么多吧.大家看完了再回去看看,注意步骤就可以了.重在理解.

好久没写了发现自己写的又挺长的,写的好累呀...希望对大家有帮助吧.

示例代码下载


参考文章:

<<asp.net服务器控件开发技术与示例>>
还有国外的两本书,一本是微软的,一本是appess的.
还有刚wrox新出的一本.名字就不多说了,想学的人,肯定找的到.

还有两篇文章
http://dev.yesky.com/msdn/335/2507335.shtml
http://dev.yesky.com/msdn/284/2505784.shtml