日期:2011-04-14  浏览次数:20515 次

第二章第二节 电子表格组件的高级功能

我们已经讨论了电子表格组件的大部分基本功能,现在让我们转向一些高级功能。大部分的这些高级功能Excel2000都不包含,因为这些是组件专门需要的特殊功能。而那些Excel2000中存在的功能,在电子表格组件中也被增强,使得可以提供一些新的功能。

属性绑定和实时数据
“属性绑定”是电子表格组件中最新奇的新功能之一,它是指控件能够将同一个web页面上其它对象的属性和方法用作单元值或公式参数的能力。电子表格控件使用标准的COM机制来实现绑定到属性,并在数据源对象告知属性值已经改变时,自动接收新值,并重新计算相关联的单元。

例如,如果您开发了一个组件,它公开了一些属性和方法以返回一个给定股票代号的最后销售价格,您就可以使用电子表格控件来查看这个信息,并在价格更新时观察到它的变化。如果电子表格的其它部分――例如当前用户的组合信息(译者注:金融专业的术语。)――引用了这个最后销售价格值,那么电子表格组件也会在值改变时重新计算这些单元。

可以象下面这样在单元中输入一个函数来建立属性绑定:
=document.StockTicker.Quote("msft").LastSale


只要公式以“=document.”开始,电子表格组件就认为紧接着的是一个属性绑定。它会认为表达式的下一部分将是页面上另一个元素的ID,而表达式的其余部分将会该元素的一个属性,或是由一个方法返回的另一元素的一个属性。您可以在方法调用中使用单元引用作为参数,而电子表格控件必然会将真实的值传递给方法。

单元绑定到的对象既可以是另一个COM对象,也可以是页面上的任何HTML元素,例如一个文本框或一个下拉列表。这样您就可以直接在重算模型中包含页面上其它的数据,而不必写脚本来将HTML元素的值输入到电子表格单元中。

属性绑定机制经常在提供实时数据的环境中被提到,因为它包含了实现提供动态数据的两个必须的特性。
l 当得知属性被修改时,电子表格组件立刻更新单元,而不会有一个固定的轮询间隔。
l “即使用户在编辑其它单元,或执行命令时”,电子表格组件依然会继续监听新值并更新单元。人们对Excel的DDE链接机制的一个普遍抱怨就是它不能完成这个功能,因此我们确信应该在电子表格控件的属性绑定特性中避免同样的错误。

属性绑定可以指向电子表格组件自身吗?
大胆的读者可能已经在思考将电子表格组件中的单元绑定到组件本身,或绑定到另一个电子表格组件上的可能性。(thinking wildly)从表面上看,似乎可以通过这个机制,轻松的支持关联不同的电子表格上的单元。
但是,唉,这是不可能的。电子表格控件自身禁止了这种支持,因为可能造成的重入引用和循环引用是相当恐怖的。电子表格控件只知道它被绑定到另一个对象上(不是自身或另一个电子表格控件)――因此它无法确保引用没有产生会挂起重算链的一个依赖循环。

为了实现将当前电子表格组件中的单元关联到另一个电子表格组件的单元上,您必须在另一个组件中通过代码来响应Change事件,并将新值写入到相关联的单元中。
当然,请记住电子表格组件处理属性变化通知的能力完全依赖于它重算当前模型的时间。对于中小型的模型来说,通常不存在问题,因为重算只会花费一秒或者更少的时间――比起大多数人所能容忍的数据更新时间要快的多。然而,如果模型相当巨大,电子表格控件也只能尽快重算来提供新数值,这可能就比新值到达的速度慢多了。

在第十章将讲述关于属性绑定的更多细节,在该章中,您将看到如何在Visual Basic中建立一个股票行情控制系统,为股票组合表格提供实时的报价。


函数插件
和在Excel中一样,开发者可以使用函数插件,将新功能添加到电子表格组件中。与符合Excel私有的XLL模型的插件不同,电子表格组件的函数插件是以COM对象的方式被创建的。这种对象所公布的任何方法都以内部函数的形式被添加(译者注:什么是potential function?),这样您就可以在公式中象使用那些Excel内部函数一样使用它。
例如,如果您开发了一个COM对象,包含了一个叫做SumTopN的方法,该方法根据传入的一列数值返回前N位数值的和,那么您可以在电子表格组件中通过下列代码来使用这个函数,就像在Window_onLoad事件中一样:
Spreadsheet1.AddIn MyObject


MyObject变量应该指向自定义函数对象的一个实例。为了保证您的对象可用,在页面上使用<object>标签,并将对象的id传给电子表格控件的AddIn方法,如下所示:
<object classid="clsid:0002E510-0000-0000-C000-000000000046"
id=Spreadsheet1>
</object>
<object classid="clsid:ClsidOfYourObject"
codebase=PathToCABfileOfYourObject id=MyObject>
<script language=VBScript>
Spreadsheet1.AddIn MyObject.Object
</script>


<object>标签中的codebase属性告诉IE如果客户端机器上没有class ID所引用的对象,应该从哪里去安装这个对象。如果需要了解更多关于codebase属性的信息,可以查看MSDN库中的IE和DHTML主题。

只有在Internet Explorer或其它使用不同的界面来包装对象的容器中需要使用Object属性。在我们刚才讨论的HTML文件中,MyObject实际上指向了一个称作object的COM对象类型(由<object>标签声明),而不是标签创建的实际COM对象。Object属性返回一个指向实际的COM对象的指针。
在Visual Basic中,您还是需要调用AddIn方法,但是需要传递一个指向您创建的类的实例的变量。例如:
Dim MyAddIn As New FunctionLib
Spreadsheet1.AddIn MyAddIn



在C++中,技巧是一样的,不过您应该使用coCreateInstance函数并向AddIn方法传递指向您的对象的IDispatch接口的引用。

电子表格组件实际上使用这种插件机制来装载不常使用的函数。Owc主要的dll文件Msowc.dll并没有实现电子表格控件的所有函数,那些不常使用的函数实际上是由Msowcf.dll来实现的(“f”代表扩展函数库);当第一次使用它们时电子表格组件自动将他们添加到插件列表中。扩展函数通过包含一系列方法的COM对象实现,其中,每一个方法对应一个公布的函数。

您可能会怀疑是否函数插件与之前所描述的属性绑定机制有所不同。答案是肯定的。属性绑定监听值改变时数据源的通知信息,而函数插件仅在函数的输入变化(或影响输入的单元变化)时被调用。这基本上是推模式和拉模式的区别:属性绑定类似推模式;当它认为必要时会将新值推入电子表格控件中。而另一方面,函数插件没有到电子表格组件的通讯通道;电子表格组件决定什么时候需要调用插件函数来计算新值。

有时推和拉的界限是模糊的,尤其是当您意识到IE将页面上的脚本函数以对象的方式暴露出来,这种能力所造成的奇怪而相当有趣的副效果时。您页面上的所有各种<script>块都以被名为Script的DOM对象公布出来,在<script>块中定义的每一个函数或子方法都被当作Script对象的一个方法。这就意味这您可以将您页面上的脚本函数用作您电子表格中的函数,不过您来完成这个功能的机制更像是属性绑定,而不是插件函数。

例如,假设您在页面上有这样一个<script>块:
<script language="VBScript">
Function VBDateAdd(interval, number, date)
On Error Resume Next
VBDateAdd = DateAdd(interval, number, date)
End Function
</script>


电子表格组件不包括复杂