Asp.net 2.0 自定义控件开发[开发一个图表(WebChart)控件(柱状图示例)](示例代码下载)
2008-04-09 23:16
1311 查看
(一). 概述
本文主要演示一个比较简单的 WebChart 柱状实现, 可以一方面了解一个较完整的控件开发实例,
里面用到了复合样式及视图存储等内容. 另一方面了解一下WebChart的实现原理. 在Web开发中, 最终
是用浏览器呈现各种图表, 图表控件呈现过程是 根据控件提供的属性接口接收到数据参数, 用最基本的
Html元素
本文主要演示一个比较简单的 WebChart 柱状实现, 可以一方面了解一个较完整的控件开发实例,
里面用到了复合样式及视图存储等内容. 另一方面了解一下WebChart的实现原理. 在Web开发中, 最终
是用浏览器呈现各种图表, 图表控件呈现过程是 根据控件提供的属性接口接收到数据参数, 用最基本的
Html元素
来呈现图表. 注: 本文参考 [Asp.net 2.0高级编程] 方案, 由于本书中配套代码说明链接打不开, 所以在文章最后面可以 下载我上传的自己做得比较完整的示例代码. (二). 运行效果 1. 在浏览器中运行的柱状图 2. 主要属性 ( 可以通过修改这些属性参数修改其 外观样式和文本显示格式等信息) 主要属性用法介绍: [align=right]
(三). 代码 代码比较简单, 就两个文件; 主要代码, 都包含了中文注释. 在这里对代码不作多介绍. 1. 主控件文件 SimpleGaugeBar.cs 代码 [align=center] 1 namespace KingControls 2 { 3 /// 4 /// Author: [ ChengKing(ZhengJian) ] 5 /// Blog: Http://blog.csdn.net/ChengKing 6 /// 本代码 参照 Asp.net 2.0高级编程 方案 7 /// 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 /// 24 /// 进度条值 25 /// 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 /// 46 /// 全值 47 /// 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 /// 66 /// 表示进度条分几段 67 /// 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 /// 90 /// 文本呈现格式 91 /// 92 public string FormatString 93 { 94 get 95 { 96 object o = this.ViewState["FormatString"]; 97 if (o == null) 98 { 99 return "{0}/{1}"; 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 /// 169 /// 在Web开发中,用Table/TR/TD来表示图形输出 170 /// 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 /// 199 /// 用Label来呈现文本,如: { 8/10 } 200 /// 201 /// 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 /// 292 /// 创建最外Table的第二行, 显示文本 293 /// 294 /// 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 /// 328 /// 增加样式 329 /// 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 [/align] 2. 复合样式文件 TextItemStyle.cs 代码 [align=center] 1 namespace KingControls 2 { 3 /// 4 /// Author: [ ChengKing(ZhengJian) ] 5 /// Blog: Http://blog.csdn.net/ChengKing 6 /// 本代码 参照 Asp.net 2.0高级编程 方案 7 /// 8 /// 9 /// 定义 SimpleGaugeBar 控件的内部复合属性类 10 /// 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 }[/align] (四). 扩展功能 通过看上面代码可以看到, 您可能会想到那些第三方公司开发的 WebChart 控件可以显示各种各样的复杂 图形, 而且不仅仅是柱状图, 还有饼状, 折线图, 甚至是 三维图形. 以上代码仅演示了一个横向的单柱形图的做法. 但已经足够说明实现一个 Chart 的过程. 如果感兴趣, 您可 以试着扩展它, 比如: 先实现把示例代码的 横向柱状图变为 竖向的柱状图; 再自己试着做一个 组合控件, 将多 个本控件整合成一个可以同时显示多列的统计分析图; 更广一点, 再考虑做一个 饼图, 折线图等. (五). 示例代码下载 http://www.cnblogs.com/Files/MVP33650/SimpleGaugeBarControl.rar (六). 控件开发其它相关文章: http://blog.csdn.net/ChengKing/category/288694.aspx 相关文章推荐
|