来呈现图表. 注: 本文参考 [Asp.net 2.0高级编程] 方案, 由于本书中配套代码说明链接打不开, 所以在文章最后面可以 下载我上传的自己做得比较完整的示例代码. (二). 运行效果 1. 在浏览器中运行的柱状图 2. 主要属性 ( 可以通过修改这些属性参数修改其 外观样式和文本显示格式等信息) 主要属性用法介绍: | | 设置显示的文本格式, 如: “68 of 100” | | | | 每段值, 如上图中设置了 10. 这样根据Maximum的值控件就能够算出共有 100/10=10段(全值共有10个td呈现) | | | | | | 柱装有效值长度标志颜色(根据Value值决定其长度) | | | | | (三). 代码 代码比较简单, 就两个文件; 主要代码, 都包含了中文注释. 在这里对代码不作多介绍. 1. 主控件文件 SimpleGaugeBar.cs 代码 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> " )] 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 2. 复合样式文件 TextItemStyle.cs 代码 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 } (四). 扩展功能 通过看上面代码可以看到, 您可能会想到那些第三方公司开发的 WebChart 控件可以显示各种各样的复杂 图形, 而且不仅仅是柱状图, 还有饼状, 折线图, 甚至是 三维图形. 以上代码仅演示了一个横向的单柱形图的做法. 但已经足够说明实现一个 Chart 的过程. 如果感兴趣, 您可 以试着扩展它, 比如: 先实现把示例代码的 横向柱状图变为 竖向的柱状图; 再自己试着做一个 组合控件, 将多 个本控件整合成一个可以同时显示多列的统计分析图; 更广一点, 再考虑做一个 饼图, 折线图等. (五). 示例代码下载 (六). 控件开发其它相关文章: Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1786409 |