现在,就可以看出ApplyStyle与MergeStyle的区别了。
三.WebControl是如何把样式生成委托给ControlStyle属性的
接下来,我们来分析WebControl是如何把样式生成后给ControlStyle属性的。在WebControl的AddAttributesToRender方法中,它调用了ControlStyle 属性的AddAttributesToRender方法。
protected virtual void AddAttributesToRender(HtmlTextWriter writer)
{
 。。。。。。。。。。。。。
。。。。。
 if (this.ControlStyleCreated && !this.ControlStyle.IsEmpty) //是否已经创建了控件样式
 {
 this.ControlStyle.AddAttributesToRender(writer, this);
}
。。。。。。。。。。。
。。。。
}
public bool ControlStyleCreated
{
 get
 {
 return (this.controlStyle != null);
 }
}
 
前面说过。WebControl中的样式属性实际上是ControlStyle属性的子属性,ControlStyle属性 AddAttributesToRender方法实现了把这些属性作为控件标签中的HTMl或Css来生成逻辑。
四.样式的状态管理
WebControl是如何把与样式相关的状态管理委托给ControlStyle属性来完成的呢?从前面我们可以看到ControlStyle属性的Style类型实现了IStateManager接口,并对自身进行状态管理。在TrackViewState,SaveViewState,LoadViewState方法中,WebControl调用了ControlStyle属性的相应方法,
为了在WebControl实现状态管理,在Style中有两个构造器,一个只有一个StateBag类型的参数,另一个没有任何参数。当在CreateControlStyle中创建控件的样式时,WebControl使用的是一个参数的构造器,把自已的ViewState传给该构造器,
protected virtual StyleCreateControlStyle()
{
 return new Style(this.ViewState);
}
 
Style的两个构造函数:
publicStyle(StateBag bag)
{
 。。
 GC.SuppressFinalize(this);
}
 
 
publicStyle() : this(null)
{
 ,。。。
}
五:重写样式属性
 样式属性的重载与其他属性的重写类似,但必须记住一点:就是对属性值的所估摸的修改必须给控件的ControlStyle属性。
 示例:
我们举一个了简单示例。
控件代码
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
/**//// 
/// LabelStyle 的摘要说明
/// 
/// 
namespace cnblogs.sui
{
 public class LabelStyle :Label
 {
 public LabelStyle()
 {
 base.BorderColor = System.Drawing.Color.Red;
 base.ForeColor = System.Drawing.Color.Red;
 //
 // TOD 在此处添加构造函数逻辑
 //
 }
 public override System.Drawing.Color BorderColor
 {
 get
 {
 return base.BorderColor;
 }
 set
 {
 throw new NotSupportedException("can not set BorderColor");
 }
 }
 public override System.Drawing.Color ForeColor
 {
 get
 {
 return base.ForeColor;
 }
 set
 {
 base.ForeColor = value;
 }
 }
 }
}
Aspx页面: <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<%@ Register Namespace="cnblogs.sui" TagPrefix="lab" %>
 无标题页
 
 在构造器中,LabelStyle对基类的BorderColor设置成Color.Red,该值将委托给ControlStyle属性,通过在LabelStyle构造器中
设置基类的BorderColor,ForeColor,把新的值传给ControlStyle属性,它把新的值传给出ControlStyle属性,该属性负责状态管理以
及样式属性的生成,如果没有把改变传到ControlStyle那么重载的样式属性就不会控预期的那样显示。 
六.实现自定义类型化样式
 继承自Style类的类称为类型化样式。Style类可以由控件开发人员来扩展,创建一个自定义类型化样式,它重写或者添加Style类的属性。服务器控件也可以把自定义类型化样式作为ControlStyle属性的类型。例如,Table控件的ControlStyle属性就是TableStyle类型,该类型是扩展的Style,添加了例如CellPadding、CellSpacing和GridLines属性等。在初步了解类型化样式属性的基本概念之后,下面列举了实现类型化样式属性的方法要点。
1、创建一个派生类自System.Web.UI.WebControl.Style的类
2、定义样式为控件提供属性
3、重写Reset方法,
4. 重写AddAttributesToRender方法,产生 HTML和CSS
5. 复制定义的属性或给定样式属性合并
示例:创建一个MyPanel控件,及相关联的类型化样式MypanelStyle,这个MyPanel控件并从WebControl继承,在MyPanelStyle中设置了3个样式属性。
 (1)BackImageUrl,用于指定背景图片的URL;
   (2)HorizontalAlign,用于指定所添加内容的水平对其方式;
   (3)Wrap,用于指定是否允许对所添加的内容换行
效果如下:
 
 
 
下面是整个的源代码:
控件代码:
控件代码
 1using System;
 2using System.Data;
 3using System.Configuration;
 4using System.Web;
 5using System.Web.Security;
 6using System.Web.UI;
 7using System.Web.UI.WebControls;
 8using System.Web.UI.WebControls.WebParts;
 9using System.Web.UI.HtmlControls;
 10using System.ComponentModel;
 11/**//// 
 12/// MyPanel 的摘要说明
 13/// 
 14/// 
 15namespace cnblogs.sui
 16{
 17
 18 MyPanelStyle#region MyPanelStyle
 19
 20 public class MypanelStyle :Style
 21 {
 22 //定义内部属性
 23 internal const int PROP_BACKIMAGEURL = 1;
 24 internal const int PROP_HORIZOHTALALIGN = 2;
 25 internal const int PROP_WRAP = 3;
 26 构造函数#region 构造函数
 27 public MypanelStyle()
 28 { }
 29 public MypanelStyle(StateBag bag) : base(bag) { 
 30 }
 31 #endregion
 32 属性列表#region 属性列表
 33 [Bindable(true), Description("背影图片的url"), NotifyParentProperty(true)]
 34
 35 //背影图片
 36 public virtual string BackImageUrl {
 37
 38 get {
 39 if (IsSet(PROP_BACKIMAGEURL))
 40 {
 41 return (string)ViewState["BackImageUrl"];
 42
 43 }
 44
 45 return String.Empty;
 46 }
 47 set {
 48 ViewState["BackImageUrl"] = value;
 49 }
 50
 51 }
 52 //实现行布局属性
 53 [Bindable(true), Category("layout"), DefaultValue(HorizontalAlign.NotSet), NotifyParentProperty(true)]
 54 public virtual HorizontalAlign HorizonalAlign
 55 {
 56 get {
 57
 58 if (IsSet(PROP_HORIZOHTALALIGN))
 59 {
 60 return (HorizontalAlign)ViewState["HorizontalAlign"];
 61 }
 62 return HorizontalAlign.NotSet;
 63 }
 64
 65 set
 66 {
 67 if (value < HorizontalAlign.NotSet || value > HorizontalAlign.Justify)
 68 {
 69 throw new ArgumentOutOfRangeException("value");
 70 }
 71 ViewState["HorizontalAlign"] = value;
 72 }
 73 }
 74 //实现IsEmpty
 75 protected new internal bool IsEmpty //使用 new 修饰符显式隐藏从基类继承的成员
 76 {
 77
 78 get {
 79
 80 return base.IsEmpty && !IsSet(PROP_BACKIMAGEURL) && IsSet(PROP_HORIZOHTALALIGN) && IsSet(PROP_WRAP);
 81
 82 }
 83 }
 84 //实现换行
 85 [Bindable(true), Category("layout"), DefaultValue(true), NotifyParentProperty(true)]
 86 public virtual bool Wrap {
 87
 88 get {
 89
 90 if (IsSet(PROP_WRAP))
 91 {
 92
 93 return (bool)ViewState["Wrap"];
 94 
 95 }
 96 return true;
 97 }
 98 set {
 99
100 ViewState["wrap"] =value;
101 }
102 }
103 #endregion
104 internal bool IsSet(int propNumber)
105 {
106
107 string key = null;
108 switch (propNumber)
109 {
110
111 case PROP_BACKIMAGEURL: key = "BackImageUrl";
112 break;
113 case PROP_HORIZOHTALALIGN: key = "HorizontalAlign";
114 break;
115 case PROP_WRAP: key = "Wrap";
116 break;
117 }
118 if (key != null)
119 {
120 return ViewState[key] != null;
121
122 }
123 return false;
124 }
125 //重写AddAttributesToRender方法
126 public override void AddAttributesToRender(HtmlTextWriter writer, WebControl owner)
127 {
128 if (IsSet(PROP_BACKIMAGEURL))
129 {
130 string s=BackImageUrl;
131 if (s.Length > 0)
132 {
133
134 if (owner != null)
135 {
136 s = owner.ResolveUrl(s);
137 }
138 writer.AddStyleAttribute(HtmlTextWriterStyle.BackgroundImage, "url(" + s + ")");
139
140 }
141 }
142 if (IsSet(PROP_HORIZOHTALALIGN))
143 {
144 HorizontalAlign hAlign = this.HorizonalAlign;
145
146 if (hAlign != System.Web.UI.WebControls.HorizontalAlign.NotSet)
147 {
148 TypeConverter hac = TypeDescriptor.GetConverter(typeof(HorizontalAlign));
149 writer.AddAttribute(HtmlTextWriterAttribute.Align, hac.ConvertToInvariantString(hAlign));
150 }
151 }
152
153 if (IsSet(PROP_WRAP))
154 {
155 bool wrap = Wrap;
156 if (!Wrap)
157 {
158 writer.AddAttribute(HtmlTextWriterAttribute.Nowrap, "nowwrap");
159 }
160 }
161
162
163 base.AddAttributesToRender(writer, owner);
164 }
165 public override void CopyFrom(Style s)
166 {
167 if (s != null)
168 { 
169 base.CopyFrom(s);
170 if (s is MypanelStyle)
171 {
172
173 MypanelStyle mps = (MypanelStyle)s;
174 if (!mps.IsEmpty)
175 {
176 if (mps.IsSet(PROP_BACKIMAGEURL))
177 this.BackImageUrl = mps.BackImageUrl;
178 if (mps.IsSet(PROP_HORIZOHTALALIGN))
179 this.HorizonalAlign = mps.HorizonalAlign;
180 if (mps.IsSet(PROP_WRAP))
181 this.Wrap = mps.Wrap;
182
183 }
184 }
185 }
186 
187 }
188
189 // 重写MergeWith方法
190 public override void MergeWith(Style s)
191 {
192 if (s != null)
193 {
194 if (IsEmpty)
195 {
196 CopyFrom(s);
197 return;
198 }
199 base.MergeWith(s);
200 if (s is MypanelStyle)
201 {
202 MypanelStyle mps = (MypanelStyle)s;
203 if (!mps.IsEmpty)
204 {
205 if (mps.IsSet(PROP_BACKIMAGEURL) && !this.IsSet(PROP_BACKIMAGEURL))
206 this.BackImageUrl = mps.BackImageUrl;
207 if (mps.IsSet(PROP_HORIZOHTALALIGN) && !this.IsSet(PROP_HORIZOHTALALIGN))
208 this.HorizonalAlign = mps.HorizonalAlign;
209 if (mps.IsSet(PROP_WRAP) && !this.IsSet(PROP_WRAP))
210 this.Wrap = mps.Wrap;
211 }
212 }
213 }
214 }
215
216 //重写Reset方法
217 public override void Reset()
218 {
219 base.Reset();
220 if (IsEmpty) return;
221 if (IsSet(PROP_BACKIMAGEURL))
222 ViewState.Remove("BackImageUrl");
223 if (IsSet(PROP_HORIZOHTALALIGN))
224 ViewState.Remove("HorizontalAlign");
225 if (IsSet(PROP_WRAP)) ViewState.Remove("Wrap");
226 }
227
228 public void Method()
229 {
230 throw new System.NotImplementedException();
231 }
232
233
234
235
236
237
238 }
239 #endregion
240
241 [ ParseChildren(false), PersistChildren(true) ]
242 [ToolboxData("<{0}:panel runat=server>{0}:panel>")]
243
244 public class MyPanel : WebControl
245 {
246 // 定义构造函数
247 public MyPanel() : base(HtmlTextWriterTag.Div) { }
248 // 实现属性BackImageUrl
249 [Bindable(true)]
250 [Category("Appearance")]
251 [DefaultValue("")]
252 public virtual string BackImageUrl
253 {
254 get
255 {
256 if (ControlStyleCreated)
257 {
258 return ((MypanelStyle)ControlStyle).BackImageUrl;
259 }
260 return String.Empty;
261 }
262 set
263 {
264 ((MypanelStyle)ControlStyle).BackImageUrl = value;
265 }
266 }
267 // 实现属性HorizontalAlign
268 [Bindable(true)]
269 [Category("Layout")]
270 [DefaultValue("")]
271 public virtual HorizontalAlign HorizontalAlign
272 {
273 get
274 {
275 if (ControlStyleCreated)
276 {
277 return ((MypanelStyle)ControlStyle).HorizonalAlign;
278 }
279 return HorizontalAlign.NotSet;
280 }
281 set
282 {
283 ((MypanelStyle)ControlStyle).HorizonalAlign = value;
284 }
285 }
286 // 实现属性Wrap
287 [Bindable(true)]
288 [Category("Layout")]
289 [DefaultValue("")]
290 public virtual bool Wrap
291 {
292 get
293 {
294 if (ControlStyleCreated)
295 {
296 return ((MypanelStyle)ControlStyle).Wrap;
297 }
298 return true;
299 }
300 set
301 {
302 ((MypanelStyle)ControlStyle).Wrap = value;
303 }
304 }
305 protected override Style CreateControlStyle()
306 {
307 return new MypanelStyle(ViewState);
308 }
309
310 }
311}
Aspx页面代码:
aspx页面
 1<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default2.aspx.cs" Inherits="Default2" %>
 2<%@ Register Namespace="cnblogs.sui" TagPrefix="panel" %>
 3
 4
 5
 6
 7 无标题页
 8
 9
10 
37
38
39
类视图:

解说一下:MyPanel类没有什么可说的,主要解析一下MypanelStyle类。继承于Style,是创建类型化样式的关键。定义一些字段与属性没有什么可说的,主要的说一下其中的方法。
1、重写了AddAttributesToRender方法。当控件呈现时生成相关的html和css。
2、重写了CopyFrom,MergeWith,Reset方法。
CopyFrom 与MergeWith是为了复制给定的MypanelStyle或把给定的MypanelStyle与自身合并。
重写Reset是为了删除添加到期ViewState 中的属性,