现在,就可以看出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 中的属性,