(一). 概述
业余时间做了一个非常有用的控件, 介绍一下.
一般当我们要实现这样一个计算功能页面:
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, 用于编译算法中存储数据结点和字符结点
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 代码
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( "" )]