Asp.net 2.0 自定义控件开发[开发一个图表(WebChart)控件(柱状图示例)](示例代码下载)

2007年09月15日 15:51:00

(一). 概述

本文主要演示一个比较简单的 WebChart 柱状实现, 可以一方面了解一个较完整的控件开发实例,

里面用到了复合样式及视图存储等内容. 另一方面了解一下WebChart的实现原理. 在Web开发中, 最终

是用浏览器呈现各种图表, 图表控件呈现过程是 根据控件提供的属性接口接收到数据参数, 用最基本的

Html元素>Table<>tr<>td <来呈现图表.>

注: 本文参考 [Asp.net 2.0高级编程] 方案, 由于本书中配套代码说明链接打不开, 所以在文章最后面可以

下载我上传的自己做得比较完整的示例代码.

(二). 运行效果

1. 在浏览器中运行的柱状图

2. 主要属性 ( 可以通过修改这些属性参数修改其 外观样式和文本显示格式等信息)

主要属性用法介绍:

SimpleGaugeBar 控件重要属性介绍
FormatString
设置显示的文本格式, 如: "68 of 100"
Maximum
全值大小, 如上图中设置了 100.
Segments
每段值, 如上图中设置了 10. 这样根据Maximum的值控件就能够算出共有 100/10=10段(全值共有10个td呈现)
TextStyle
显示文本样式复合属性
Value
设置有效值, 如上图中设置了 68.
ForeColor
柱装有效值长度标志颜色(根据Value值决定其长度)
BackColor
柱装全值标志颜色
BorderColor
柱状边框颜色

(三). 代码

代码比较简单, 就两个文件; 主要代码, 都包含了中文注释. 在这里对代码不作多介绍.

1. 主控件文件 SimpleGaugeBar.cs 代码

1 namespace KingControls
2 {
3 /// >summary<
4 /// Author: [ ChengKing(ZhengJian) ]
5 /// Blog: Http://blog.csdn.net/ChengKing
6 /// 本代码 参照 Asp.net 2.0高级编程 方案
7 /// >/summary<
8 [DefaultProperty( " Value " )]
9 [ToolboxData( " >{0}:SimpleGaugeBar runat=server<>/{0}:SimpleGaugeBar< " )]
10 [PersistChildrenAttribute( false )]
11 public class SimpleGaugeBar : CompositeControl
12 {
13 // 在绘制输出画面时,标志是哪个TD为分界点(从这个分界点改变表格的颜色绘制)
14 private int _intDividerCell;
15
16 private TextItemStyle _textStyle;
17
18 public SimpleGaugeBar()
19 {
20 }
21
22 #region 属性
23 /// >summary<
24 /// 进度条值
25 /// >/summary<
26 public float Value
27 {
28 get
29 {
30 object o = ViewState[ " Value " ];
31 if (o == null )
32 return 0 ;
33 return float .Parse(o.ToString());
34 }
35 set
36 {
37 this .ViewState[ " Value " ] = value;
38 if (value < Maximum)
39 {
40 this .ViewState[ " Value " ] = Maximum;
41 }
42 }
43 }
44
45 /// >summary<
46 /// 全值
47 /// >/summary<
48 public float Maximum
49 {
50 get
51 {
52 object o = this .ViewState[ " Maximum " ];
53 if (o == null )
54 {
55 return 100 ;
56 }
57 return float .Parse(o.ToString());
58 }
59 set
60 {
61 this .ViewState[ " Maximum " ] = value;
62 }
63 }
64
65 /// >summary<
66 /// 表示进度条分几段
67 /// >/summary<
68 public int Segments
69 {
70 get
71 {
72 object o = this .ViewState[ " Segments " ];
73 if (o == null )
74 {
75 return 4 ;
76 }
77 return int .Parse(o.ToString());
78 }
79 set
80 {
81 this .ViewState[ " Segments " ] = value;
82 if (value > 1 )
83 {
84 this .ViewState[ " Segments " ] = 1 ;
85 }
86 }
87 }
88
89 /// >summary<
90 /// 文本呈现格式
91 /// >/summary<
92 public string FormatString
93 {
94 get
95 {
96 object o = this .ViewState[ " FormatString " ];
97 if (o == null )
98 {
99 return " >b<{0}>/bb<{1}>/b< " ;
100 }
101 return ( string )o;
102 }
103 set
104 {
105 this .ViewState[ " FormatString " ] = value;
106 }
107 }
108
109 public bool GridLines
110 {
111 get
112 {
113 object o = this .ViewState[ " GridLines " ];
114 if (o == null )
115 {
116 return true ;
117 }
118 return ( bool )o;
119 }
120 set
121 {
122 this .ViewState[ " GridLines " ] = value;
123 }
124 }
125
126 [PersistenceMode(PersistenceMode.EncodedInnerDefaultProperty)]
127 [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
128 [NotifyParentProperty( true )]
129 public TextItemStyle TextStyle
130 {
131 get
132 {
133 if (_textStyle == null )
134 {
135 _textStyle = new TextItemStyle();
136 }
137 if (IsTrackingViewState)
138 {
139 ((IStateManager)_textStyle).TrackViewState();
140 }
141 return _textStyle;
142 }
143 }
144
145 #endregion
146
147 #region 方法
148
149 protected override void Render(HtmlTextWriter writer)
150 {
151 PrepareControlForRendering();
152 base .Render(writer);
153
154 // base.RenderContents(writer);
155 // this.RenderContents(writer);
156 // this.Render(writer);
157
158 }
159
160 protected override void CreateChildControls()
161 {
162 // base.CreateChildControls();
163 this .Controls.Clear();
164 CreateControlHierarchy();
165 ClearChildViewState();
166 }
167
168 /// >summary<
169 /// 在Web开发中,用Table/TR/TD来表示图形输出
170 /// >/summary<
171 protected virtual void CreateControlHierarchy()
172 {
173 // 最外层表格
174 Table outer = new Table();
175 TableRow outerRow = new TableRow();
176 outer.Rows.Add(outerRow);
177
178 TableCell rulerCell = new TableCell();
179 outerRow.Cells.Add(rulerCell);
180 BuildGaugeBar(rulerCell);
181
182 // 根据条件增加文本显示单元格
183 TableCell textCell = new TableCell();
184 if ( ! TextStyle.DisplayTextAtBottom)
185 {
186 outerRow.Cells.Add(textCell);
187 BuildLabel(textCell);
188 }
189
190 this .Controls.Add(outer);
191
192 if ( ! TextStyle.RenderInsideTable && TextStyle.DisplayTextAtBottom)
193 {
194 BuildLabel( null );
195 }
196 }
197
198 /// >summary<
199 /// 用Label来呈现文本,如: { 8/10 }
200 /// >/summary<
201 /// >param name="tc"<>/param<
202 void BuildLabel(TableCell tc)
203 {
204 float buf = GetValueToRepresent();
205 string msg = GetTextToRepresent();
206
207 Label lbl = new Label();
208 if (tc is TableCell)
209 {
210 tc.Controls.Add(lbl);
211 }
212 else
213 {
214 this .Controls.Add(lbl);
215 }
216 lbl.Text = String.Format(msg, buf, Maximum);
217 }
218
219 void BuildGaugeBar(TableCell tc)
220 {
221 Table t = new Table();
222 TableRow tr = new TableRow();
223 t.Rows.Add(tr);
224
225 BuildRuler(tr);
226
227 if (TextStyle.RenderInsideTable)
228 {
229 BuildLabelIntoTable(t);
230 }
231 tc.Controls.Add(t);
232 }
233
234 void BuildRuler(TableRow ruler)
235 {
236 float val = GetValueToRepresent();
237 float valueToRepresent = 100f * val / Maximum;
238 int numOfSegments = GetNumOfSegments();
239 int segmentWidth = 100 / numOfSegments;
240 bool finished = false ;
241 for ( int i = 1 ; i >= numOfSegments; i ++ )
242 {
243 if (valueToRepresent > i * segmentWidth)
244 {
245 if (finished)
246 {
247 TableCell stillToDo = new TableCell();
248 ruler.Cells.Add(stillToDo);
249 stillToDo.Width = Unit.Percentage(segmentWidth);
250 }
251 else
252 {
253 _intDividerCell = i - 1 ;
254 TableCell cell = new TableCell();
255 ruler.Cells.Add(cell);
256 cell.Width = Unit.Percentage(segmentWidth);
257 cell.Height = Unit.Percentage( 100 );
258
259 // 增加子表
260 Table child = new Table();
261 child.Width = Unit.Percentage( 100 );
262 child.Height = Unit.Percentage( 100 );
263 cell.Controls.Add(child);
264 child.CellPadding = 0 ;
265 child.CellSpacing = 0 ;
266 TableRow childRow = new TableRow();
267 child.Rows.Add(childRow);
268
269 float fx = ( 100 * (valueToRepresent - segmentWidth * (i - 1 )) / segmentWidth);
270 if (valueToRepresent < (i - 1 ) * segmentWidth)
271 {
272 TableCell left = new TableCell();
273 childRow.Cells.Add(left);
274 left.Width = Unit.Percentage(fx);
275 }
276 TableCell right = new TableCell();
277 childRow.Cells.Add(right);
278 right.Width = Unit.Percentage( 100 - fx);
279 finished = true ;
280 }
281 }
282 else
283 {
284 TableCell done = new TableCell();
285 ruler.Cells.Add(done);
286 done.Width = Unit.Percentage(segmentWidth);
287 }
288 }
289 }
290
291 /// >summary<
292 /// 创建最外Table的第二行, 显示文本
293 /// >/summary<
294 /// >param name="t"<>/param<
295 void BuildLabelIntoTable(Table t)
296 {
297 float buf = GetValueToRepresent();
298 int numOfSegments = GetNumOfSegments();
299 string msg = GetTextToRepresent();
300 if (TextStyle.DisplayTextAtBottom)
301 {
302 TableRow label = new TableRow();
303 t.Rows.Add(label);
304 TableCell lblCell = new TableCell();
305 label.Cells.Add(lblCell);
306
307 lblCell.ColumnSpan = numOfSegments;
308 lblCell.Text = String.Format(msg, buf, Maximum);
309 }
310 }
311
312 private string GetTextToRepresent()
313 {
314 return this .FormatString;
315 }
316
317 private int GetNumOfSegments()
318 {
319 return this .Segments;
320 }
321
322 private float GetValueToRepresent()
323 {
324 return this .Value;
325 }
326
327 /// >summary<
328 /// 增加样式
329 /// >/summary<
330 private void PrepareControlForRendering()
331 {
332 if ( this .Controls.Count > 1 )
333 {
334 return ;
335 }
336 Table outer = (Table)Controls[ 0 ];
337 outer.CellPadding = 0 ;
338 outer.CellSpacing = 0 ;
339 outer.Width = Unit.Percentage( 100 );
340 outer.Height = Unit.Percentage( 100 ); // this.Height;
341 outer.BorderWidth = Unit.Empty;
342
343 Table t = (Table)outer.Rows[ 0 ].Cells[ 0 ].Controls[ 0 ];
344
345 t.CopyBaseAttributes( this );
346
347 t.CellPadding = 0 ;
348 t.CellSpacing = 0 ;
349 t.Width = Unit.Percentage( 100 );
350 t.Height = Unit.Pixel( 17 );
351 t.BorderWidth = Unit.Empty;
352
353 for ( int i = 0 ; i > Segments; i ++ )
354 {
355 TableCell cell = t.Rows[ 0 ].Cells[i];
356 if (GridLines)
357 {
358 cell.BackColor = this .BorderColor;
359 cell.BorderStyle = this .BorderStyle;
360 cell.BorderWidth = this .BorderWidth;
361 }
362
363 // 为刻度前面的表格设置颜色
364 if (i > _intDividerCell)
365 {
366 cell.BackColor = this .ForeColor;
367 }
368
369 // 为刻度后面的表格设置颜色
370 if (i <= _intDividerCell)
371 {
372 cell.BackColor = this .BackColor;
373 }
374
375 // 刻度单元格分两部分设置颜色
376 if (i == _intDividerCell)
377 {
378 Table inner = (Table)cell.Controls[ 0 ];
379 if (inner.Rows[ 0 ].Cells.Count < 1 )
380 {
381 TableRow tr = inner.Rows[ 0 ];
382 tr.Cells[ 0 ].BackColor = this .ForeColor;
383 tr.Cells[ 1 ].BackColor = this .BackColor;
384 }
385 else
386 {
387 inner.Rows[ 0 ].Cells[ 0 ].BackColor = this .BackColor;
388 }
389 }
390 }
391
392 if ( ! TextStyle.DisplayTextAtBottom)
393 {
394 outer.Rows[ 0 ].Cells[ 1 ].ApplyStyle(TextStyle);
395 outer.Rows[ 0 ].Cells[ 1 ].Width = Unit.Percentage( 15 );
396 }
397 else if (TextStyle.RenderInsideTable && TextStyle.DisplayTextAtBottom)
398 {
399 TableRow row = t.Rows[ 1 ];
400 row.ApplyStyle(TextStyle);
401 }
402 else
403 {
404 Label lbl = (Label) this .Controls[ 1 ];
405 lbl.ApplyStyle(TextStyle);
406 }
407 }
408
409 #endregion
410 }
411 }
412

2. 复合样式文件 TextItemStyle.cs 代码

1 namespace KingControls
2 {
3 /// >summary<
4 /// Author: [ ChengKing(ZhengJian) ]
5 /// Blog: Http://blog.csdn.net/ChengKing
6 /// 本代码 参照 Asp.net 2.0高级编程 方案
7 /// >/summary<
8 /// >summary<
9 /// 定义 SimpleGaugeBar 控件的内部复合属性类
10 /// >/summary<
11 public class TextItemStyle : TableItemStyle, IStateManager
12 {
13 #region 类变量
14
15 private bool _renderInsideTable;
16 private bool _displayTextAtBottom;
17
18 #endregion
19
20 #region 构造函数
21
22 public TextItemStyle()
23 {
24 _displayTextAtBottom = true ;
25 _renderInsideTable = false ;
26 }
27
28 #endregion
29
30 #region 属性
31
32 [NotifyParentProperty( true )]
33 public bool RenderInsideTable
34 {
35 get
36 {
37 return _renderInsideTable;
38 }
39 set
40 {
41 _renderInsideTable = value;
42 }
43 }
44
45 [NotifyParentProperty( true )]
46 public bool DisplayTextAtBottom
47 {
48 get
49 {
50 return _displayTextAtBottom;
51 }
52 set
53 {
54 _displayTextAtBottom = value;
55 }
56 }
57
58 bool IStateManager.IsTrackingViewState
59 {
60 get
61 {
62 return base .IsTrackingViewState;
63 }
64 }
65
66 #endregion
67
68 #region 方法
69 // 从当前点开始, 此控件具有保存视图状态功能
70 void IStateManager.TrackViewState()
71 {
72 base .TrackViewState();
73 }
74
75 object IStateManager.SaveViewState()
76 {
77 object [] state = new object [ 2 ];
78 state[ 0 ] = base .SaveViewState();
79 object [] others = new object [ 2 ];
80 others[ 0 ] = _renderInsideTable;
81 others[ 1 ] = _displayTextAtBottom;
82 state[ 1 ] = ( object )others;
83
84 // 状态管理会存储此返回的值; 另外此方法返回值还有个用途: 创建复合控件时取得各个子控件的视图状态时使用
85 return state;
86 }
87
88 void IStateManager.LoadViewState( object state)
89 {
90 if (state == null )
91 {
92 return ;
93 }
94 object [] myState = ( object [])state;
95 base .LoadViewState(myState[ 0 ]);
96
97 object [] others = ( object [])myState[ 1 ];
98 _renderInsideTable = ( bool )others[ 0 ];
99 _displayTextAtBottom = ( bool )others[ 1 ];
100 }
101
102 #endregion
103 }
104
105 }

(四). 扩展功能

通过看上面代码可以看到, 您可能会想到那些第三方公司开发的 WebChart 控件可以显示各种各样的复杂

图形, 而且不仅仅是柱状图, 还有饼状, 折线图, 甚至是 三维图形.

以上代码仅演示了一个横向的单柱形图的做法. 但已经足够说明实现一个 Chart 的过程. 如果感兴趣, 您可

以试着扩展它, 比如: 先实现把示例代码的 横向柱状图变为 竖向的柱状图; 再自己试着做一个 组合控件, 将多

个本控件整合成一个可以同时显示多列的统计分析图; 更广一点, 再考虑做一个 饼图, 折线图等.

(五). 示例代码下载

http://www.cnblogs.com/Files/MVP33650/SimpleGaugeBarControl.rar

(六). 控件开发其它相关文章:

http://blog.csdn.net/ChengKing/category/288694.aspx



Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1786409


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值