CSDN专家博客精华版

为人民服务!
  首页  :: 新随笔  :: 管理

(一). 概述

                本文主要演示一个比较简单的 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}</b>/<b>{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 的过程. 如果感兴趣, 您可

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

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

        

(五). 示例代码下载

        https://files.cnblogs.com/MVP33650/SimpleGaugeBarControl.rar

 

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

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

 

 

 

 

 

 

 

 

 

 

 

 

 

   

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