`
happmaoo
  • 浏览: 4333583 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

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

阅读更多
<iframe align="top" marginwidth="0" marginheight="0" src="http://www.zealware.com/46860.html" frameborder="0" width="468" scrolling="no" height="60"></iframe>

(一). 概述

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

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

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

scriptlanguage='javascript'>
functioncompute()
{
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.EMath.LN10Math.LN2Math.LOG10EMath.LOG2E
Math.PIMath.SQRT1_2Math.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></summary>
2///Author:[ChengKing(ZhengJian)]
3///Blog:Http://blog.csdn.net/ChengKing
4///
5///<summary></summary>
6///Node的摘要说明
7///
8///<summary></summary>
9///结点类[操作符结点]
10///

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

24}

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

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

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

1///<summary></summary>
2///Author:[ChengKing(ZhengJian)]
3///Blog:Http://blog.csdn.net/ChengKing
4///
5///<summary></summary>
6///ConvertHelper的摘要说明
7///
8///<summary></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///
18publicclassConvertHelper
19{
20///<summary></summary>
21///存放JavaScript运算符的各种结点
22///
23privatestring[]OP_Chars=newstring[7]{"+","-","*","/","(",")",","};
24
25///<summary></summary>
26///自定义变量前缀符号
27///
28privatestringVarPreSymbol="_";
29
30///<summary></summary>
31///存储要读取控件的属性(如:t.text/t.Valueetc)
32///
33privatestringValueSymbol=".value";
34
35///<summary></summary>
36///存储compute方法脚本变量
37///
38privatestringComputeScript="";
39
40///<summary></summary>
41///存储onblur方法脚本变量
42///
43privatestringOnblurScript="";
44
45///<summary></summary>
46///区别于方法名的序列号[依次递增,如:compute1,compute2,compute3]
47///
48privateintSequenceNum=1;
49
50///<summary></summary>
51///抽取出运算符结点[其中包括运算符结点的位置信息]
52///
53///
54///<returns></returns>
55privateListNode>BuildOPNode(stringstrObject)
56{
57intbeginIndex=0;//记录当前处理结点的起始索引
58ListNode>nodes=newListNode>();
59
60
61while(true)
62{
63if(beginIndex==strObject.Length)
64{
65break;
66}
67
68for(intj=0;jOP_Chars.Length;j++)
69{
70if(strObject.Length-beginIndex>=OP_Chars[j].Length)
71{
72if(OP_Chars[j]==strObject.Substring(beginIndex,OP_Chars[j].Length))
73{
74//操作符
75Nodenode=newNode(beginIndex,beginIndex+OP_Chars[j].Length-1,strObject.Substring(beginIndex,OP_Chars[j].Length));
76nodes.Add(node);
77break;
78}
79}
80}
81beginIndex++;
82}
83returnnodes;
84}
85
86///<summary></summary>
87///根据运算符结点抽取出数据结点[其中包括数据结点的位置信息]
88///
89///
90///<returns></returns>
91publicListNode>BuildDataNode(stringstrObject)
92{
93strObject=ClearSpace(strObject);
94ListNode>dataNodes=newListNode>();
95ListNode>opNodes=this.BuildOPNode(strObject);
96
97//考虑表达式最左边是数据结点情况,如:A+B表达式中的A
98if(opNodes.Count>0&&opNodes[0].startIndex!=0&&opNodes[0].str!="(")
99{
100stringstr=strObject.Substring(0,opNodes[0].startIndex);
101if(this.JudgeFigure(str)==false&&this.IsIndexOfMath(str)==false)
102{
color: #008080
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics