现在的位置: 首页 > 综合 > 正文

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

2013年09月08日 ⁄ 综合 ⁄ 共 3601字 ⁄ 字号 评论关闭

(一). 概述

         前几天做了一个自定义控件AutoComputeControl, 具体请见: 

                  http://blog.csdn.net/ChengKing/archive/2007/04/12/1562765.aspx 

        在读本文章之前请先读一下上面链接所指向的文章.

        此控件在99%情况下, 能够很方便地处理页面上TextBox控件之间的自动计算. 但有一种情况, 它有点不完善.

        举例, 假如要计算这样的表达式, 如图:

       

        从图上可以看出, 要同时计算的两个表达式中, 其中 ID为:price 的TextBox同时参与了两个表达式的运算.

       如果按上个控件的计算方法, 经过编译分析表达式后最终是产生的脚本如下:

      

        由控件自动生成的JavaScript可以看出, 脚本代码能够正确的生成; 但发现一个小问题, price控件同时注册了两个onblur事件, 也就是说当price控件失去焦点时要同时执行方法compute1和compute2, 结果才能够计算正确;  但基于JavaScript语法限制, 当注册我个onblur方法(别的事件也一样)时, 默认最后一个起效, 也就是说在上面的代码中, 当price 控件失去焦点时, 只有compute2方法计算, 从程序逻辑讲这是不合理的.

        基于此, 我又采用了新设计方案. 下面就详细说一下新的设计思路. 在看代码以前请先看看新的设计思路文档. 新生成的JS代码也会在下面发布.

(二). 新设计方案文档      

     1). 自动完成组件功能概述

 

u       通过使用场景理解:

1.         举例: 页面上有一组控件, 其中包括: 五个TextBox控件, 并且它们的ID属性依次为: A B C D E; 另外有个表达式控件F(此控件带个表达式属性, 用来建立要计算的控件的值之间的运算关系). 其中表达式属性设置为: A*(B+C) *D*0.98 + E ; 另外本控件还用来存储显示的计算结果.

      


2.         功能描述: 当页面运行时, 修改A B C D E控件值(比如: A=5, B=6, …), 并且A B C D E等其中任一个控件失去焦点时, E控件会根据表达式重新计算更新到最新值.

3.         以上a) b)是用一组控件(只含一组表达式)进行示例, 它还支持页面上同时放置多组表达式控件, 并且组间控件能够进行交叉.

      

4.         运行状态, 支持嵌套表达式运算. 比如TextBox控件中也能够输入表达式(比如: A中输入的不是6, 而是6*(8+2)). 也能够正确计算出结果.

      

u      实现方案概要

运行时只需设置一个属性:  运算表达式字串, 以下简称 Expression.

其中E包括了本自动计算组件所需的两个重要参数条件: 1. 控件的ID;  2. 控件之间的关系运算, 以下就是通过这两个参数条件进行展开运算.

算法概要流程图:

                                                                        (图一)

1.         Expression用编译算法进行扫描, 区分出:

哪些是: 数据结点(用于输入数据的控件, : A B C D ETextBox控件);

哪些是: 运算符(JavaScript中的运算符, : + - * / )

                     并确定每个数据结点在E中的起始/结束位置索引等信息.

2.         根据 a) 得出的数据信息和运算表达式运算关系, C# 动态生成每组控件的计算表达式JavaScrpt代码, 并注册A B C D ETextBox控件的引发事件, 组装成的JavaScript脚本格式如下

      

 1 //计算表达式代码
 2 <script language='javascript'> 
 3  function compute1() 
 4  { 
 5   var _C = parseFloat(eval(document.getElementById('C').value));
 6   var _D = parseFloat(eval(document.getElementById('D').value));
 7   document.getElementById('A').value=_C+_D;
 8  }
 9 </script>
10 
11 <script language='javascript'> 
12  function compute2() 
13  { 
14   var _A = parseFloat(eval(document.getElementById('A').value));
15   var _E = parseFloat(eval(document.getElementById('E').value));
16   document.getElementById('B').value=_A*_E;
17  }
18 </script>
19 
20 //注册引发事件
21 <script language='javascript'> 
22  function onblurA() 
23  { 
24   compute1();
25   compute2();
26  }
27 </script>
28 

    

                                       (代码一)

 

        注意: 表达式不是固定不变的, 在运行状态, 动态改变表达式字串属性, 动态

         生成的JavaScript也不同. 可以任意改变计算表达式之间的运算关系.

 

    2). 详细设计算法流程图

 

u       编译字符串算法

Ø         得到操作符结点信息(+-*/)

扫描字符串, 当遇到有操作符字符{ "+", "-", "*", "/", "(", ")", "," },

其存储到数组中.

Ø         根据以上得到的操作符信息集合, 得到数据结点信息(A B C D ETextBoxID)

算法规则概述:

       一般情况下, 两个操作符(+-*/)之间的字符串为[数据变量结点(: A B CTextBoxID)], 但下面几种情况要排除:

a)       提取的相邻字符中, 右边字符为"("操作符时, 中间不是数据变量结点.

b)       两个操作符的索引位置相邻时, 其中间没有字符串, 显然也就没有数据变量结点.

c)       数据变量结点必须是字符串变量, 不能为数值字符串(:568).

d)       排除Math.E等常量情况,因为这些常量也满足条件1, 包括(Math.E/Math.LN10/Math.LN2/Math.LOG10E/Math.LOG2E/ Math.PI/Math.SQRT1_2/Math.SQRT2).

 

u       注册生成JavaScript算法

Ø         生成并注册客户端脚本Compute核心方法

根据上一步编译字符串得到的数据结点和运算关系, C#组装生成并注册一系列的Compute方法, 为避免多个表达式之间的冲突, 这里用累计数值的方式, :第一个表达式生成的计算方法为Compute1(){}, 第二个为: Compute2(){}, 第三个为: Compute3(){} .

具体代码格式请看上面的: (代码一).

Ø         生成并注册客户端脚本Onblur方法.

Compute, 也是根据编译字符串得到的数据结点和运算关系表达式来用C#

组装生成客户端能够直接运行的JavaScript脚本. 其中数据结点控件 B 生成的代码格式如下:

 1 <script type="text/javascript">
 2 <!--
 3   document.getElementById('B').onblur=onblurB;
 4 // -->
 5 </script>
 6 
 7 <script language='javascript'> 
 8  function onblurB() 
 9  { 
10   compute1();
11   compute2();
12   compute1();
13  }
14 </script>
15 
 

                  (代码二)

 

 

这里算法比较复杂, 下面举两个例子描述一下, 请先看一个运行的示例界面:

 

其中左边五个TextBoxID从上到下依次为: A B C D E;

右边的TextBox表示: A的值 = 下面的C的值 + D的值.

                   B的值 = 下面的A的值 * E的值.

                   .

抱歉!评论已关闭.