Asp.net 2.0 自定义控件开发[实现自动计算功能(AutoComputeControl)][示例代码下载]

(一). 概述        

 业余时间做了一个非常有用的控件, 介绍一下.
         一般当我们要实现这样一个计算功能页面:
                      TextBox1(单价)  
* TextBox2(数量) = TextBox3(总和);
        并且当在TextBox1或TextBox2中输入数据, 鼠标离开时, TextBox3控件能够即时重新计算新值(乘积).

       一般我们的做法步骤是:
              
1. 拖三个控件到页面上, 默认三个TextBox控件ID分别为: TextBox1, TextBox1, 
                  TextBox3.

              
2. 写个JavaScript 函数, 能够计算 TextBox1和TextBox2的乘积, 并赋值给TextBox3
                  即时最新值.

                      
<script language='javascript'> 
                          function compute() 
                          {
                                  var _num 
= parseFloat(document.getElementById('TextBox1').value);
                                  var _price 
= parseFloat(document.getElementById('TextBox2').value);
                                  document.getElementById(
'TextBox3').value=_num*_price;
                         }
                      
</script>

              
3. 注册TextBox1和TextBox2的onblur事件(TextBox控件失去焦点时触发).
                  
this.TextBox1.Attributes.Add("onblur","compute()");
                  
this.TextBox2.Attributes.Add("onblur","compute()"); 

             OK, 这样固然能够完成.  也存在以下缺点:
             
1. 不够通用, 如果好多页面都需要这么一个控件,  那得写上面这些代码到所有
                 页面中. 开发效率不高. 且容易出错.

             
2. 页面中代码比较乱. 嵌入好多JavaScript代码. 难以维护.
             
3. 假如运算表达式非常复杂[如:  A*B+(B*C)+Math.E  ] 每次设置JS也比较麻烦.

            基于以上缺陷,   
            下面是一个通用的自定义控件AutoComputeControl(自动计算),  能够弥补以上缺点, 
    且具有通用性, 

            特点如下:
              
1. 使用简单,  只需设置一个表达式属性Expression, 控件能够自动完成所有JS脚本.
                  其中表达式由: 运算符和变量组成(控件的ID), 等一下会详细介绍使用方法.

              
2. 不仅支持简单运算, 更大的优势是支持复杂表达式, 如:

                  price
*(num+2*(3+6))*Math.E = sum ,  即
                 TextBox1
*(TextBox2+2*(3+6)) * Math.E =TextBox3            

                  仅通过将控件的: ID和运算符 任意组合成计算表达式赋值给控件Expression属性, 

                  其它的工作由本控件来完成, 本控件能够自动生成所有JS脚本. 并最终在页面客
     户端呈现.  

             
3. 另外, 支持Math对象下面的属性和方法:
                       Math属性:   Math.E    Math.LN10 Math.LN2  Math.LOG10E  Math.LOG2E  
                                             Math.PI   Math.SQRT1_2     Math.SQRT2

                      Math方法:    Math.abs(x)   Math.acos(x)   Math.asin(x)   Math.atan(x)   
                                             Math.atan2(x,y)    Math.ceil(x)   Math.floor(x)   Math.cos(x) 
                                             Math.exp(x)   Math.log(x)   Math.max(x,y)   Math.min(x,y)   
                                             Math.pow(x,y)   Math.random()   Math.round(
20.49)   Math.sin(x)
                                             Math.sqrt(x)   Math.tan(x)

                       例如:   Math.sin(Math.sqrt(price1
*price2))+Math.E*num=sum

                           即    Math.sin(Math.sqrt(TextBox1
*TextBox2))+Math.E*TextBox3=TextBox4

             4. 最终用户还可以在控件中输入表达式:

                      例如, 用户在TextBox1框中输入: 6*(5+2)

                              再在TextBox2中输入: 3+Math.E*Math.PI

                              再把表达式: TextBox1*(TextBox2+2*(3+6)) * Math.E =TextBox3            

                              赋值给本控件属性Expression, 仍然能够正确计算出结果.

             5. 在一个页面中放多个本控件.

                 比如: 拖个本控件到页面跟 TextBox1/TextBox2/TextBox3 组合,

                         再拖另一个控件跟另一组  TextBox4/TextBox5/TextBox5  组合.

                 注意: 不要两组表达式产生冲突, 比如把TextBox1即在第一组又在

                         第二组, 这样脚本生成是正确的, 但这样自动生成的客户端脚本, 会

                         为TextBox1注册两个onblur事件, 那么默认第二个onblur起效, 不能

                         同时起效.  这是JavaScript 语法规定的.  

                                                


          实现原理:   本自定义控件的Expression属性, 如: TextBox1*(TextBox2+TexBox3)*0.90=TextBox4

                             中包括:

                                  1. 控件的ID.  2. 表达式之间的关系.

                             然后自定义控件内核代码会:

                                  1. 用编译算法扫描表达式属性(Expression)值, 分析运算关系.

                                  2. 根据运算关系动态生成要呈现到客户端的JavaScript, 再最终由自定义控件呈现.

(二).  使用步骤

         1. 拖三个TextBox控件到页面上,  如图:

        2. 设置TextBox1的ID属性为: price;   TextBox2的ID属性为: num;  TextBox3的ID属性为: sum.

        3. 再添加一个AutoCompute控件(本文章主讲控件), 并设置其: Expression 属性值为:

             price * num = sum ,  意思是: [单价] * [数量] = [总额]

        4. 运行即可.  运行后当输入[单价]和[数量]时, 程式能够自动计算[总额]的值.

            测试: 当鼠标从[单价]或[数量]控件失去焦点时, 总额值能够重新被计算显示.

       5. 扩展: 

               a. 您也可以输入更复杂的表达式, 比如从上面DropDownList(测试用的控件)里面随便选几个.

               b. 不仅能够计算三个TextBox的表达式(如上), 您还可以添加N个TextBox表达式.

        功能比较强大吧  :) :) 

(三). 表达式规则:

        支持JavaScript运算规则,  并支持Math对象的所有属性和方法.

(四). 核心代码

       1. Node类文件Node.cs, 用于编译算法中存储数据结点和字符结点

 1 /// <summary>
 2    /// Author: [ ChengKing(ZhengJian) ] 
 3    /// Blog:   Http://blog.csdn.net/ChengKing
 4    /// </summary>
 5    /// <summary>
 6    /// Node 的摘要说明
 7    /// </summary>
 8    /// <summary>
 9    /// 结点类[操作符结点] 
10    /// </summary>

11      public   class  Node
12      {
13        public string str;       //存储本节点字串
14        public int startIndex;   //用于存储一个结点所在[运算表达式]的开始索引位置
15        public int endIndex;     //用于存储一个结点所在[运算表达式]的结束索引位置    
16
17
18        public Node(int startIndex, int endIndex, string str)
19        {
20            this.str = str;
21            this.startIndex = startIndex;
22            this.endIndex = endIndex;        
23        }

24    }

       2. 主要控件类 AutoCompute.cs 代码

 1  ///   <summary>
 2       ///  Author: [ ChengKing(ZhengJian) ] 
 3       ///  Blog:   Http://blog.csdn.net/ChengKing
 4       ///   </summary>
 5      [DefaultProperty( " Text " )]
 6      [ToolboxData( " <{0}:AutoCompute runat=server></{0}:AutoCompute> " )]
 7       public   class  AutoCompute : Control
 8      {
 9          [Bindable( true )]
10           // [Category("外观")]
11          [DefaultValue( " [AutoCompute / " AutoCompute1/ " ] " )]
12          [Localizable( true )]
13           public   string  Text
14          {
15               get
16              {
17                  String s  =  (String)ViewState[ " Text " ];
18                   return  ((s  ==   null ?  String.Empty : s);
19              }
20 
21               set
22              {
23                  ViewState[ " Text " =  value;
24              }
25          }
26 
27          [Bindable( true )]        
28          [DefaultValue( "" )]
29          [Localizable( true )]
30           public   string  Expression
31          {
32               get
33              {
34                   string  s  =  ( string ) this .ViewState[ " Expression " ];
35                   return  ((s  ==   null ?  String.Empty : s);
36              }
37               set
38              {
39                   this .ViewState[ " Expression " =  value;
40              }
41          }
42 
43           protected   override   void  Render(HtmlTextWriter writer)
44          {
45               if  (DesignMode)
46              {
47                   this .Controls.Clear();
48                  LiteralControl lc  =   new  LiteralControl();
49                  lc.Text  =   this .Text;
50                   this .Controls.Add(lc);
51              }         
52               base .Render(writer);
53          }
54 
55           protected   override   void  OnPreRender(EventArgs e)
56          {
57               base .OnPreRender(e);
58 
59              ConvertHelper _ConvertHelper  =   new  ConvertHelper();
60               string  strClientScript;
61               try
62              {
63                   if  ( this .Expression.Trim().Length  !=   0 )
64                  {
65                      _ConvertHelper.Main(Page,  this .Expression);
66                      _ConvertHelper.RegisterClientScript( this .Page);
67                  }
68                   else
69                  {
70                      strClientScript  =   "    alert('No Set [Expression] Property!'); " ;
71                       if  ( ! Page.ClientScript.IsStartupScriptRegistered( " Default_Property " ))
72                      {
73                          Page.ClientScript.RegisterStartupScript( this .GetType(),  " Default_Property " , strClientScript,  true );
74                      }
75                  }
76              }
77               catch
78              {
79                  strClientScript  =   "    alert('The [Expression] format is not correct!'); " ;
80                   if  ( ! Page.ClientScript.IsStartupScriptRegistered( " Default_Property " ))
81                  {
82                      Page.ClientScript.RegisterStartupScript( this .GetType(),  " Default_Property " , strClientScript,  true );
83                  }
84              }
85 
86          }
87 
88      }

       3. ConvertHelper.cs类文件, 主要实现编译算法以及JavaScript脚本生成注册功能.

  1    ///   <summary>
  2       ///  Author: [ ChengKing(ZhengJian) ] 
  3       ///  Blog:   Http://blog.csdn.net/ChengKing
  4       ///   </summary>
  5       ///   <summary>
  6       ///  ConvertHelper 的摘要说明
  7       ///   </summary>
  8       ///   <summary>
  9       ///  算法概述:
 10       ///   引用概念: [数据变量结点]: 用户命名的字串, 如: total = price*num, 则 "price" 字串就为数据变量结点
 11       ///   1. 抽取出操作运算符. 并记住所有运算符的索引
 12       ///   2. 两个操作符之间的字符串为[数据变量结点(用户命名的字串)], 但下面几种情况要排除:
 13       ///        a. 提取的相邻字符中, 右边字符为"("操作符时, 中间不是数据变量结点.
 14       ///        b. 两个操作符相邻时, 其中间没有字符串, 显然也就没有数据变量结点.
 15       ///        c. 数据变量结点必须是字符串变量, 不能为数值.
 16       ///        d. 排除Math.E等常量情况(Math.E/Math.LN10/Math.LN2/Math.LOG10E/Math.LOG2E/ Math.PI/Math.SQRT1_2/Math.SQRT2).
 17       ///   </summary>
 18       public   class  ConvertHelper
 19      {
 20           ///   <summary>
 21           ///  存放JavaScript运算符的各种结点
 22           ///   </summary>
 23           private   string [] OP_Chars  =   new   string [ 7 ] {  " + " " - " " * " " / " " ( " " ) " " , "  };
 24 
 25           ///   <summary>
 26           ///  自定义变量前缀符号
 27           ///   </summary>
 28           private   string  VarPreSymbol  =   " _ " ;
 29 
 30           ///   <summary>
 31           ///  存储要读取控件的属性(如: t.text/t.Value etc)
 32           ///   </summary>
 33           private   string  ValueSymbol  =   " .value " ;
 34 
 35           ///   <summary>
 36           ///  存储compute方法脚本变量
 37           ///   </summary>   
 38           private   string  ComputeScript  =   "" ;
 39 
 40           ///   <summary>
 41           ///  存储onblur方法脚本变量
 42           ///   </summary>   
 43           private   string  OnblurScript  =   "" ;
 44 
 45           ///   <summary>
 46           ///  区别于方法名的序列号[依次递增, 如: compute1, compute2, compute3  ]
 47           ///   </summary>
 48           private   int  SequenceNum  =   1 ;
 49 
 50           ///   <summary>
 51           ///  抽取出运算符结点[其中包括运算符结点的位置信息]
 52           ///   </summary>
 53           ///   <param name="strObject"></param>
 54           ///   <returns></returns>
 55           private  List < Node >  BuildOPNode( string  strObject)
 56          {
 57               int  beginIndex  =   0 // 记录当前处理结点的起始索引       
 58              List < Node >  nodes  =   new  List < Node > ();
 59 
 60 
 61               while  ( true )
 62              {
 63                   if  (beginIndex  ==  strObject.Length)
 64                  {
 65                       break ;
 66                  }
 67 
 68                   for  ( int  j  =   0 ; j  <  OP_Chars.Length; j ++ )
 69                  {
 70                       if  (strObject.Length  -  beginIndex  >=  OP_Chars[j].Length)
 71                      {
 72                           if  (OP_Chars[j]  ==  strObject.Substring(beginIndex, OP_Chars[j].Length))
 73                          {
 74                               // 操作符
 75                              Node node  =   new  Node(beginIndex, beginIndex  +  OP_Chars[j].Length  -   1 , strObject.Substring(beginIndex, OP_Chars[j].Length));
 76                              nodes.Add(node);
 77                               break ;
 78                          }
 79                      }
 80                  }
 81                  beginIndex ++ ;
 82              }
 83               return  nodes;
 84          }
 85 
 86           ///   <summary>
 87           ///  根据运算符结点抽取出数据结点[其中包括数据结点的位置信息]
 88           ///   </summary>
 89           ///   <param name="strObject"></param>
 90           ///   <returns></returns>
 91           public  List < Node >  BuildDataNode( string  strObject)
 92          {
 93              strObject  =  ClearSpace(strObject);
 94              List < Node >  dataNodes  =   new  List < Node > ();
 95              List < Node >  opNodes  =   this .BuildOPNode(strObject);
 96 
 97               // 考虑表达式最左边是数据结点情况, 如: A+B 表达式中的A
 98               if  (opNodes.Count  >   0   &&  opNodes[ 0 ].startIndex  !=   0   &&  opNodes[ 0 ].str  !=   " ( " )
 99              {
100                   string  str  =  strObject.Substring( 0 , opNodes[ 0 ].startIndex);
101                   if  ( this .JudgeFigure(str)  ==   false   &&   this .IsIndexOfMath(str)  ==   false )
102                  {
103                      Node node  =   new  Node( 0 , opNodes[ 0 ].startIndex  -   1 , str);
104                      dataNodes.Add(node);
105                  }
106 
107              }
108 
109               // 根据操作运算符求得中间的一系列数据结点
110               for  ( int  i  =   0 ; i  <  opNodes.Count  -   1 ; i ++ )
111              {
112                   if  ( this .IsDataNodeBetweenOPNodes(opNodes[i], opNodes[i  +   1 ], strObject))
113                  {
114                      Node node  =   new  Node(opNodes[i].endIndex  +   1 , opNodes[i  +   1 ].startIndex  -   1 , strObject.Substring(opNodes[i].endIndex  +   1 , opNodes[i  +   1 ].startIndex  -  opNodes[i].endIndex  -   1 ));
115                      dataNodes.Add(node);
116                  }
117              }
118 
119               // 考虑最右端是数据结点情况, 如: A+B 表达式中的B
120               if  (opNodes.Count  >   0   &&  (opNodes[opNodes.Count  -   1 ].endIndex  !=  strObject.Length  -   1 ))
121              {
122                   string  str  =  strObject.Substring(opNodes[opNodes.Count  -   1 ].endIndex  +   1 );
123                   if  ( this .JudgeFigure(str)  ==   false   &&   this .IsIndexOfMath(str)  ==   false )
124                  {
125                      Node node  =   new  Node(opNodes[opNodes.Count  -   1 ].endIndex  +   1 , strObject.Length  -   1 , str);
126                      dataNodes.Add(node);
127                  }
128              }
129               return  dataNodes;
130          }
131 
132           ///   <summary>
133           ///  判断相邻结点中间是否是数据结点
134           ///   </summary>
135           ///   <param name="leftNode"></param>
136           ///   <param name="rightNode"></param>
137           ///   <returns></returns>
138           ///   根据以下定理进行判断
139           ///     a. 提取的相邻字符中, 右边字符为"("操作符时, 中间不是数据变量结点.
140           ///     b. 两个操作符相邻时, 其中间没有字符串, 显然也就没有数据变量结点.
141           ///     c. 数据变量结点必须是字符串变量, 不能为数值.
142           ///     d. 排除Math.E等常量情况(Math.E/Math.LN10/Math.LN2/Math.LOG10E/Math.LOG2E/ Math.PI/Math.SQRT1_2/Math.SQRT2).
143           private   bool  IsDataNodeBetweenOPNodes(Node leftNode, Node rightNode,  string  strObject)
144          {
145               // 条件a
146               if  (rightNode.str  ==   " ( " )
147              {
148                   return   false ;
149              }
150 
151               // 条件b
152               if  (leftNode.endIndex  +   1   ==  rightNode.startIndex)
153              {
154                   return   false ;
155              }
156 
157               // 条件c
158               if  ( this .JudgeFigure(strObject.Substring(leftNode.endIndex  +   1 , rightNode.startIndex  -  leftNode.endIndex  -   1 ))  ==   true )
159              {
160                   return   false ;
161              }                   
162              
163               if  ( this .IsIndexOfMath(strObject.Substring(leftNode.endIndex  +   1 , rightNode.startIndex  -  leftNode.endIndex  -   1 )))
164              {
165                   return   false ;
166              }
167 
168               return   true ;
169          }
170 
171           ///   <summary>
172           ///  //判断是否Math.开头 排除(Math.E/Math.LN10/Math.LN2/Math.LOG10E/Math.LOG2E/ Math.PI/Math.SQRT1_2/Math.SQRT2)等常量
173           ///   </summary>
174           ///   <param name="str"></param>
175           ///   <returns></returns>
176           public   bool  IsIndexOfMath( string  str)
177          {
178               if  (str.IndexOf( " Math. " ==   0 )
179              {
180                   return   true ;
181              }
182               return   false ;
183          }
184 
185           ///   <summary>
186           ///  判断是否是数字
187           ///   </summary>
188           ///   <param name="str"></param>
189           ///   <returns></returns>
190           private   bool  JudgeFigure( string  str)
191          {
192               if  (str.Trim().Length  <=   0 )
193                   return   true ;
194               int  dot  =   0 ;
195               if  (str[ 0 ==   ' . '   ||  str[str.Length  -   1 ==   ' . ' )
196                   return   false ;
197               for  ( int  i  =   0 ; i  <  str.Length; i ++ )
198              {
199                   if  (dot  >   1 return   false ;
200                   if  (Char.IsDigit(str, i))
201                  {
202                       continue ;
203                  }
204                   if  (str[i]  ==   ' . ' )
205                  {
206                      dot  =  dot  +   1 ;
207                       continue ;
208                  }
209                   return   false ;
210              }
211               return   true ;
212          }
213 
214           ///   <summary>
215           ///  返回处理后的表达式
216           ///   </summary>
217           ///   <param name="str"></param>
218           ///   <param name="?"></param>
219           ///   <returns></returns>
220           private   string  CreateClientScript(Page page,  string  strAll, List < Node >  nodes)
221          {
222               string  strLeft  =  strAll.Substring( 0 , strAll.IndexOf( " = " )); ;
223               string  strRight  =  strAll.Substring(strAll.IndexOf( " = " ) + 1 );
224 
225               ///   <summary>
226               ///  生成并注册compute方法脚本
227               ///   </summary>
228               int  intNumDataNodeCount  =  nodes.Count;
229 
230               // 调整方法名, 防止多个表达式运算时, 方法名冲突
231               while  ( true )
232              {
233                   // bool flag = page.ClientScript.IsClientScriptBlockRegistered("compute" + SequenceNum.ToString());
234                   if  ( ! page.ClientScript.IsClientScriptBlockRegistered( this .GetType(),  " compute "   +  SequenceNum.ToString()))
235                  {
236                       if  ( ! page.ClientScript.IsStartupScriptRegistered( this .GetType(),  " onblur "   +   this .SequenceNum.ToString()))
237                      {
238                           break ;
239                      }
240 
241                  }
242                  SequenceNum ++ ;
243              }
244 
245               // 生成脚本头JS字串
246               string  strJSHead  =   " <script language='javascript'> /n function compute "   +   this .SequenceNum.ToString()  +   " () /n { /n " ;            
247               // 生成脚本体JS字串
248               string  strJSBody  =   "" ;
249               for  ( int  i  =   0 ; i  <  intNumDataNodeCount; i ++ )
250              {
251                  strJSBody  +=   "   var  "   +  VarPreSymbol  +  nodes[i].str  +   "  = parseFloat(document.getElementById(' "   +  ((Control)page.FindControl(nodes[i].str)).ClientID  +   " ') "   +  ValueSymbol  +   " );/n " ;  
252              }
253              strJSBody  +=   "   document.getElementById(' "   +  ((Control)page.FindControl(strRight)).ClientID  +   " ') "   +  ValueSymbol; 
254              strJSBody  +=   " = " ;
255 
256               for  ( int  i  =   0 ; i  <  intNumDataNodeCount; i ++ )
257              {
258                  strLeft  =  strLeft.Remove(nodes[i].startIndex, nodes[i].str.Length);
259                  strLeft  =  strLeft.Insert(nodes[i].startIndex,  " _ "   +  nodes[i].str);
260                   this .RepairNodes( ref  nodes, i  +   1 );
261              }
262              strLeft  +=   " ; " ;
263              strJSBody  +=  strLeft;
264               string  strJSFoot  =   " /n }/n</script>/n/n " ;
265 
266               string  strReturnScript  =  strJSHead  +  strJSBody  +  strJSFoot;
267               this .ComputeScript  =  strReturnScript;
268 
269 
270 
271               ///   <summary>
272               ///  生成并注册onblur脚本(调用compute方法)
273               ///   </summary>
274               string  strOnBlur  =   " /n<script language='javascript'>/n " ;
275               for  ( int  i  =   0 ; i  <  nodes.Count; i ++ )
276              {                
277                  strOnBlur  +=   "   document.getElementById(' "   +  ((Control)page.FindControl(nodes[i].str)).ClientID  +   " ') "   +   " .οnblur=compute "   +   this .SequenceNum.ToString()  +   " ;/n " ;
278              }
279              strOnBlur  +=   " </script> " ;
280               this .OnblurScript  =  strOnBlur;
281 
282 
283 
284              strReturnScript  +=  strOnBlur;
285               return  strReturnScript;
286          }
287 
288           ///   <summary>
289           ///  重新调整数据节点集合的索引值
290           ///   </summary>
291           ///   <param name="nodes"></param>
292           ///   <param name="index"></param>
293           private   void  RepairNodes( ref  List < Node >  nodes,  int  index)
294          {
295               for  ( int  i  =  index; i  <  nodes.Count; i ++ )
296              {
297                   // 6相当于前面数据结点插入的 ".value" 的长度
298                  nodes[i].startIndex  =  nodes[i].startIndex  +  VarPreSymbol.Length;
299                  nodes[i].endIndex  =  nodes[i].endIndex  +  VarPreSymbol.Length;
300              }
301          }
302 
303           public   string  Main(Page page,  string  strAll)
304          {
305              strAll  =   this .ClearSpace(strAll);
306               if  (CheckParenthesesMatching(strAll)  ==   false )
307              {
308                  page.Response.Write( " <br><br><br><br><br> 括号不匹配! " );
309                   return   "" ;
310              }
311 
312               string  strLeft  =  strAll.Substring( 0 , strAll.IndexOf( " = " ));
313 
314               string  strEndJS_Script  =   this .CreateClientScript(page, strAll, BuildDataNode(strLeft));
315               return  strEndJS_Script;
316          }
317 
318           // 检查括号是否匹配
319           private   bool  CheckParenthesesMatching( string  strCheck)
320          {
321               int  number  =   0 ;
322               for  ( int  i  =   0 ; i  <  strCheck.Length; i ++ )
323              {
324                   if  (strCheck[i]  ==   ' ( ' ) number ++ ;
325                   if  (strCheck[i]  ==   ' ) ' ) number -- ;
326                   if  (number  <   0 return   false ; // 右括号不能在前面
327              }
328               if  (number  !=   0 )
329              {
330                   return   false ;
331              }
332               return   true ;
333          }
334 
335           // 消去空格
336           private   string  ClearSpace( string  str)
337          {
338               return  str.Replace( "   " "" );
339          }
340 
341           // 注册客户端脚本
342           public   bool  RegisterClientScript(Page page)
343          {
344               if  ( this .OnblurScript.Length  ==   0   ||   this .ComputeScript.Length  ==   0 )
345              {
346                   return   false ;
347              }
348 
349               if  ( ! page.ClientScript.IsClientScriptBlockRegistered( " compute "   +   this .SequenceNum.ToString()))
350              {
351                  page.ClientScript.RegisterClientScriptBlock( this .GetType(),  " compute " this .ComputeScript,  false );
352              }
353 
354               if  ( ! page.ClientScript.IsStartupScriptRegistered( " onblur "   +   this .SequenceNum.ToString()))
355              {
356                  page.ClientScript.RegisterStartupScript( this .GetType(),  " onblur " this .OnblurScript,  false );
357              }
358               return   true ;
359          }
360 
361      }

 

(五). 示例代码下载

        http://www.cnblogs.com/Files/MVP33650/自动计算控件.rar  

(六). 其它相关自定义控件文章

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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值