惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

D
DataBreaches.Net
N
Netflix TechBlog - Medium
P
Proofpoint News Feed
D
Docker
J
Java Code Geeks
L
LangChain Blog
Microsoft Security Blog
Microsoft Security Blog
The GitHub Blog
The GitHub Blog
I
InfoQ
Stack Overflow Blog
Stack Overflow Blog
云风的 BLOG
云风的 BLOG
Engineering at Meta
Engineering at Meta
MongoDB | Blog
MongoDB | Blog
月光博客
月光博客
T
Tailwind CSS Blog
M
MIT News - Artificial intelligence
Blog — PlanetScale
Blog — PlanetScale
Google DeepMind News
Google DeepMind News
腾讯CDC
罗磊的独立博客
U
Unit 42
爱范儿
爱范儿
Vercel News
Vercel News
MyScale Blog
MyScale Blog

博客园 - yiriqing

DataMining with Sql 2005 建立Microsoft SQL Server 2005数据仓库 C#应用访问Microsoft SQL Server 2005分析服务 一步一步学Remoting之一:从简单开始 Programming MS Office 2000 Web Components第二章第一节(第三部分) Programming MS Office 2000 Web Components第二章第一节(第二部分) Programming MS Office 2000 Web Components第四章第六节 Programming Microsoft Office 2000 Web Components 第四章第五节 Programming MS Office 2000 Web Components第四章第三节 Programming MS Office 2000 Web Components第四章第二节 Programming MS Office 2000 Web Components第四章第一节 Programming MS Office 2000 Web Components第三章第三节 Programming MS Office 2000 Web Components第三章第二节 Programming MS Office 2000 Web Components第三章第一节 Programming MS Office 2000 Web Components第二章第三节 Programming MS Office 2000 Web Components第二章第二节 Programming MS Office 2000 Web Components第一章第三节 Programming Microsoft Office 2000 Web Components第一章第一节 绑定到数据源 Office XP 图表组件
Programming MS Office 2000 Web Components第二章第一节
yiriqing · 2006-06-19 · via 博客园 - yiriqing

第二章 电子表格组件

       本章将深入探讨微软Office电子表格组件的功能和编程模式。因为本书关注于建立实际的解决方案,所以我将展示一些各个组件特性的有趣用法,并进行说明。在本书第二部分,您会看到许多用法的使用。

       本章将向您展示数据表格组件能够做什么,不能做什么,向您推荐使用自己的代码为组件添加功能的聪明方法,以及向您展示使用电子表格组件编程模式的关键所在,这可是您学习电子表格组件的起点。

电子表格组件基本功能

       在我们深入了解电子表格组件的细节前,让我们先来看看它的基本功能,它所支持的装载和保存数据的各种方法。

重算引擎

       重算引擎是电子表格控件的核心—它使得组件不再仅仅是一个网格控件。因为电子表格组件是由那些为Microsoft Excel开发重算引擎的开发者开发的,所以它几乎支持Excel2000中所有的函数,包括大部分数据分析包(ATP)中的函数。

注释:

       如果您对上述内容感兴趣,请注意,下列函数不被电子表格组件所支持:ASC, CALL, DATEDIF, FINDB, FREQUENCY, GETPIVOTDATA, GROWTH, INFO, ISPMT, JIS, LEFTB, LENB, LINEST, LOGEST, MDETERM, MIDB, MINVERSE, MMULT, PHONETIC, REGISTER.ID, REPLACEB, RIGHTB, SEARCHB, SQL.REQUEST, TRANSPOSE, TREND, 和YEN。还有,所有以”B”结尾的函数都会在字节级进行操作,而不是象在双字节字符集系统中那样基于字符级。

       请参考本章后部关于属性绑定和插件函数的部分,以了解如何使用VBA和VBScript来实现这些函数。还有,在EXCEL中INDEX和LOOKUP函数都有两种形式,一种使用数组为参数,另一种使用向量(一维队列)为参数。电子表格控件支持向量参数形式,但不支持数组参数形式。

       任何包括公式的电子表格组件,在使用中都会很自然的需要重算引擎的支持――例如,一个允许用户查看产品收支平衡表,改变假设值并查看重算结果的解决方案,就会需要重算引擎。重算功能是电子表格分析的主干功能,是电子表格产品的核心功能。重算引擎也能利用本章后面会讨论到的一些先进特性,例如属性绑定和插件函数。

       当以无用户界面的方式使用电子表格组件时(即内存对象形式),重算引擎成为组件主要的服务。重算引擎能够执行任何电子表格模型中易于表达的复杂计算。也能在服务器上根据一个现有的模型重算并将显示结果发送给web浏览器或者发送到电子邮件信息中。许多计算工作,如果使用脚本或C来完成的话会十分繁琐,但是在电子表格模型中却会很容易。

       例如,银行或借贷机构可能会开发一个评估特定类型贷款风险的电子表格模型。因为借贷保险业者常常不是程序员,让他们开发服务器上运行的借贷评估函数可能会很困难――就像让不理解借贷保险业者使用的复杂计算公式的程序员来开发一样。然而,如果使用电子表格组件的重算引擎,程序员就可以加载保险业者发布的电子表格模型,改变输入值,并输出获得的新的风险评估结果。

       电子表格组件支持最大655,36行,702列(从A列到ZZ列)的工作表,但是每一个组件实例只支持一个工作表。这和Excel2000支持的行数相同,但几乎是Excel2000支持的列数的3倍。(Excel只支持256列)

       注意:

       如果您想要装载所有655,36行和702列,您会等待较长时间。因为电子表格控件是从HTML格式的数据加载它的内容,所以装载操作当然比装载二进制数据(例如Excel装载XLS文件时)慢。虽然当装载数百条记录的文件时一般相当快,但电子表格组件不能快速加载数量巨大的模型。

       电子表格控件同时支持公式中的绝对单元引用($A$1)和相对单元引用(A1),就象Excel一样,当您移动,插入,或者删除行或列时,它会自动的调整这些引用。在将包含公式的单元从区域中一个地方拷贝到另一个地方时,绝对和相对引用的使用都会相当有用。例如,在不管哪行哪列包含这个公式,引用都必须保持不变时,您应该使用绝对单元引用。而如果引用必须相对于当前的行和列,则需要使用相对引用。换句话说,在拷贝之后,$A$1还会是$A$1,而A1会变成拷贝到的当前行列。

       注释

       电子表格组件不支持旧的R1C1引用样式。它也不支持英语公式,英语公式试图使您能够根据命名了的区域来建立公式,然而它只是一个完美的目标,实际上很少如所设想的那样工作。

       很遗憾,这个版本的Office中电子表格组件不支持命名的区域。当Excel发布一个具有交互能力的电子表格模型时(换句话说,发布一个包含电子表格控件的页面),它自动将命名的区域引用转换成绝对的区域引用。当您从Excel向电子表格控件中拷贝粘贴单元时也会发生这种转换。如果您想在电子表格组件的编码中使用命名的区域时,请考虑使用Dictionary对象(Scripting.Dictionary),因为这个对象可以方便的按名存取实际的引用。(Dictionary对象位于Microsoft Scripting Runtime 库中)

       例如,如果您需要在电子表格中为一组数据定义一个命名的区域,然后在脚本中使用这个区域来完成一次排序,您可以用下列的代码来完成:

Set dict = CreateObject("Scripting.Dictionary")
dict.Add "MyName", "A1:F20"
Set rng = Spreadsheet1.Range(dict("MyName"))

       Dictionary对象是一个关联数组。可以将键/值对添加到其中,然后通过键,可以高效地重新得到任何值。使用这个对象,可以很容易跟踪命名区域,在任何需要向电子表格传递一个引用时,您可以使用上面最后一行代码中的方法来重新获得一个给定名称对应的真实引用。

电子表格组件用户界面

       电子表格组件用户界面位于重算引擎之上。当然,它和Excel的用户界面相似,但是为了支持和现有的电子表格模型交互时所需的功能,它作了特殊的设计。Excel中许多使用户可以轻易创建一个新电子表格的特性,在电子表格控件中都不存在;(然而,对于为您的解决方案创建新电子表格所必须的功能来说,它已经足够了)。还有,您可以从Excel向电子表格组件中进行拷贝和粘贴――这意味着您可以在Excel中完成大部分的创建工作。表2-1展示了一个基本的电子表格组件的例子。

       疯狂的电子表格引用

       我们能干的电子表格组件开发者之一,Andrew Milton,在检查本章时,向我展示了其它一些Excel支持而电子表格组件不支持的区域引用的类型。但这些引用方法中的大部分我从来没见过,甚至不知道在Excel中可以这样作。试试下面的步骤:

1、  在A1:A5的各单元中输入1,2,3,4,5。

2、  然后,在单元B1中输入值2。

3、  最后,在单元C1中输入公式:=SUM(A1:CHOOSE(B1, A1, A2, A3, A4, A5))。结果是3。

4、  现在,将单元B1的值改为3。单元C1中的公式将会重新计算,结果编程6。

函数CHOOSE的行为类似VBA中的Select Case语句,可以用在区域引用的中部来动态的定义区域结束的地方。也可以使用INDIRECT函数来实现动态定义区域的功能,但是电子表格组件完全不支持这种动态区域的定义。

       区域之间的交集是另一个有趣的创造。在最后那个例子中你所使用的电子表格里,如果在单元D1中键入公式“=A1:A5 A1:B1”,将得到1。此类引用使Excel计算两个区域的交集,结果就是指向A1的引用。电子表格组件允许您输入这样的公式,但是会将公式转化为“=A1”,而Excel会保留您最初输入的公式。

图2-1         一个基础的电子表格组件

       电子表格组件用户界面包含了许多被认为是理所当然的电子表格的特性。比起将每一个特性都罗列出来,我更愿意让您在使用控件时自己发现大部分的特性,虽然下列列表并不完全,但是能使您了解电子表格控件支持的用户界面特性的级别有多高。

改变行、列的大小
 透明选择(译者:当用户选择单元格时,不会隐藏格式)
 
当输入公式时辅助选择
 多级撤销
 
插入和移除行列
 剪切,拷贝和粘贴
 
基于单元的格式化,包括设置字体,背景,对齐方式等等
 全套的数字格式,包括对欧元格式的支持
 
自动过滤
 自动求和
 
对区域进行排序
 查找
 
单元边框
 隐藏或显示工具条,行、列标头以及表格线
 
合并单元格
 可选的标题栏
 
手动重算和自动重算的开关
 保护单元,能够禁止插入和删除行、列。
 
可视区域和自动调整
 在微软IE中支持按百分比缩放及最大化显示
 
内置的联机帮助
 冻结的面板
 
完全键盘支持
 可以控制滚动条的存在
 
可以控制回车后如何选择当前单元
 可在全世界各国的计算机环境中运行,支持多国语言,支持从右到左的排列

       因为电子表格组件自身并不是应用程序,只是一个控件,所以它是通过一个名为属性工具箱的非模式工具窗口提供大部分的格式化功能的。这部分的用户界面实际上由各个组件共享,无论何时,开发者或用户需要改变控件中元素的格式时都会用到它。而如果开发者需要提供一个客户化的运行时用户界面,或禁止运行时用户改变控件中的元素,也可以通过在编程模式中改变一个属性来在运行时禁止属性工具箱。(本章稍后会讲述这个过程)

       非常有趣的是,属性工具箱完全是使用动态HTML(DHTML)来编写的。电子表格组件通过寄宿Internet Explorer控件的一个实例来实现属性工具箱,并在您和web页面上的元素交互时通过控制IE控件的实例来执行属性工具箱的代码。属性工具箱只是执行依赖于OWC组件的编程模型的脚本,因此,您可以在代码中完成属性工具箱的任何功能。

       电子表格控件,以及其它的Office Web组件,都支持Office 2000的语言设置功能,因此用户可以将电子表格控件中的用户界面语言设置成和在Office应用程序中使用的一样,而不需要设置底层的系统区域。如果这些语言设置被改变了,控件会自动的调整他们的用户界面,根据所选择的语言来进行显示。这也会影响到金额,事件和数字的格式。电子表格组件支持在单元中输入Unicode字符,在需要从右到左的排列的区域环境中,它也支持从右到左排列。

 排序和过滤

       阅读本节时,如果您打开随书光盘Samples\Chap02目录下的SortFilterExample.htm文件。您会发现这个例子很有用。本节展示的代码和描述的特定环境来自这个文件。

       电子表格组件支持Excel中的基础的排序和过滤功能,并且通过编程模型和用户界面来提供这些功能。然而,在电子表格的用户界面中,排序和过滤的功能比起Excel有某种程度的增强。让我们来看一个例子。

DHTML探险

       属性工具箱是由两位OWC小组的天才程序员,Eric Matteson和Cesar Alvarez开发的不可思议的杰作,属性工具箱也证明了试图使用DHTML来模仿Office的用户界面风格是一件困难重重的事。早期,我们坚持认为我们应该使属性工具箱尽可能地和标准的Office用户界面相似,Eric和Cesar也的确花费了数月的时间来改变HTML和IE浏览器,使得它能符合需求。大多数人都不相信结果竟然就在HTML中。然而,因为考虑到虽然一般人都可以很有效的使用web站点,但还是会被Office应用程序中的许多高级对话框所迷惑,所以关于使用HTML来模拟Office用户界面是否使得控件更易于使用的争论依然很突出。

       对于那些希望在web页面中使用Office Web Components的开发者们,我的建议是不要浪费时间企图将HTML融入到传统的微软窗体应用程序的界面中,而应该利用HTML的简洁和动态布局的优势来为您的应用程序开发一个更加自然和易于使用的界面。

       假设您已经开发了一个用于列出您当前的产品线的电子表格, 表格中显示了每一个产品的单价,库存数量,和定购数量,还有一个给出了销售率的计算列,用于显示潜在的价值。现在用户需要根据产品的潜在价值对产品列表进行降序排列。用户可以在电子表格用户界面中,简单的选择需要排序的区域(或者在区域中选择任意的一些单元),并点击降序工具条按钮。当按钮被点击时,一个Excel中没有的菜单在按钮下方显示出来,如图2-2所示。

图2-2  使用中的电子表格组件用户界面

用户们在对Excel区域排序时所遇到的常见问题之一就是选择要排序的区域和选择根据哪一列进行排序。电子表格组件让用户能够方便的选择需要排序的区域,然后在用户点击工具条上的升序或降序排序按钮时,显示一个列名的列表,使用户能够选择根据哪一列进行排序。通过Range对象的Sort方法,也可以使用排序功能。它使开发人员可以在用户单击或者双击一个列标头时方便地完成一个列表的排序。

您可以已经注意到电子表格组件一次只能根据一列来对列表进行排序。Excel提供了一个排序对话框,可以让您同时根据最多三个关键列进行排序(例如,是否根据种类排序,然后根据发货人排序,最后根据潜在价值排序)。电子表格组件没有完成这个功能的用户界面,但是底层的引擎是支持这个功能的。您可以使用下列函数模仿多列的排序。

'--------------------------------------------------------------------------
' MultiColumnSort
' 目的: 同时根据多列对电子表格进行排序
' 传入:    电子表格中需要排序的区域的引用,
'          被排序的列的列编号的数组,
'          排序方向标志的数组(和上面的数组相同大小)
' 输出:     无 (完成排序动作)
'
Sub MultiColumnSort(Spreadsheet, Range, Columns, Directions)
    ' 启动一个撤消单位,以便可以以一个完整单位的任务进行撤消
    Spreadsheet.BeginUndo()
 
' 关闭ScreenUpdating属性,使得当我们设置过滤,排序
' 和再过滤时电子表格不会重画
    Spreadsheet.ScreenUpdating = False
 
    ' 现在递减遍历Columns数组和Directions数组,
    ' 实现我们需要的效果
    For ct = ubound(Columns) To lbound(Columns) Step -1
        ' 0 is a guess for column headings
        Range.Sort Columns(ct), Directions(ct), 0
    Next 'ct
    
    ' 打开ScreenUpdating属性开关,使电子表格重画
    Spreadsheet.ScreenUpdating = True
    
    ' End the undo unit
    Spreadsheet.EndUndo()    
    
End Sub 'MultiColumnSort()

       实现多列排序的技巧在于,实际上是按照被排序列所定义次序的相反次序执行排序动作。例如,如果您需要先根据类别进行排序,然后再根据发货商进行排序,函数则会首先根据发货商排序列表,然后再根据类别进行排序。当电子表格根据一个新列排序列表时,新列的每一项(新列中相同列值的一组行)中,之前根据另一列进行排序产生的次序将保持不变。我们刚才阅读的函数接收三个参数:一个需要排序的区域,一个列编号的数组,一个方向值的数组(降序或升序)。函数降序遍历这两个数组,从而实现了多列排序的效果。请注意,函数还使用了BeginUndo和EndUndo方法来将所有的排序操作组合在一个撤消动作块中,这样当用户选择撤消命令时,这些排序动作就会被一起撤消。

       电子表格组件也支持一种新的自动过滤的用户界面。组件中的过滤函数和Excel中的过滤函数相似,但是组件用户界面中的自动过滤下拉列表有一些不同的地方。假设您需要从图2-2中我们刚才查看过的产品列表中,过滤掉一些产品类别来观察它会怎样影响高潜在价值的产品。开发者或用户可以打开自动过滤功能,在类别列上点击自动过滤箭头,就会看到图2-3所示的界面。

图2-3.         电子表格组件的自动过滤用户界面

       在Excel中,可以非常方便的选择单个项,然而,选择多项则需要使用高级自动筛选对话框,当您只是想要排除四五项时,这个操作就会十分费劲。而在电子表格组件中,自动过滤下拉列表为每一项都提供了一个简化复选框,在顶部还有一个”显示所有”项,使您能够快速切换所有项的状态(选择或不选择)。

       机敏的读者会发现电子表格组件中的自动过滤下拉列表没有包括Excel中很有用的两个设置选项。例如,您找不到”前10位”的选项,这个选项使您能够快速过滤,得到前10位(或者前n位)的项。您也找不到”自定义”的选项,这个选项允许您完成比简单的包含或不包含的过滤复杂得多的过滤功能。很遗憾,这些更高级的功能还没有包含在电子表格组件中。不过,您可以通过调用电子表格控件的编程模型来容易得模拟这些功能。

    可以使用下列函数来模拟”前n位”的过滤功能:

'--------------------------------------------------------------------------
' TopNFilter
' 目的: 根据给定的列编号过滤出列表的前N项
' 输入:    电子表格和区域的引用、列编号, 
'          要过滤出的行的行数,以及标识过滤出前N行还是后N行的方向值
' Out:     无 (完成所需的过滤)
'
Sub TopNFilter(Spreadsheet, Range, ColumnNum, N, Direction)
    Set c = Spreadsheet.Constants
    Set rngData = Range
    Set af = Spreadsheet.ActiveSheet.AutoFilter
    
    ' 启动一个撤消单元,以便将来能以完整的单元进行撤消
    Spreadsheet.BeginUndo()
 
' 关闭ScreenUpdating属性开关,使得当我们在设置过滤,排序和再次应用
    '过滤时,电子表格不会重画
    Spreadsheet.ScreenUpdating = False
    
    ' 清除任何现存的过滤定义
    ClearFilters Spreadsheet
 
    ' 在给定的数据区域中根据传入的列号的列排序列表
    If LCase(Direction) = "bottom" Then
        rngData.Sort ColumnNum, c.ssAscending, c.ssNo
    Else
        rngData.Sort ColumnNum, c.ssDescending, c.ssNo
    End If
    
    '如果N+1,N+2等等的行和第N行的值相同,
'则”前N位”过滤的结果可以会包含多过N的行。
'因此循环查看N+1等行是否和第N行的值相同,
'直到查找到一个不相同的值为止。
    vNValue = rngData.Cells(N,ColumnNum).Value
    
    While rngData.Cells(N+1,ColumnNum).Value = vNValue
        N = N + 1
    Wend
    
    'N现在的值就是我们需要包括在过滤结果中的行的行数。
    Set fltr = af.Filters(ColumnNum)
    fltr.Criteria.FilterFunction = c.ssFilterFunctionInclude
    
    For ct = 1 To N
        fltr.Criteria.Add(rngData.Cells(ct,ColumnNum).Text)
    Next
    
    ' 最后引用自动过滤
    af.Apply
 
    ' 打开ScreenUpdating属性开关,使电子表格重画
    Spreadsheet.ScreenUpdating = True
    
    ' 结束撤消单元
    Spreadsheet.EndUndo()
 
End Sub 'TopNFilter()

       “前N位”过滤功能似乎很简单,只要先排序,然后查看最开始的N行即可。但是真正的”前N位”过滤功能可能会返回超过N行的结果,因为它实际上的意思是”包括前N位的值的那些行”。如果在排序后,第10,11位的值相同,那么”前10位”过滤会将这些产品一起返回,因为它们都在前10位的值当中。还有,上述代码通过简单的改变排序方向(升序和降序)实现了过滤出前N位和后N位的功能。

    同样地,您可以通过使用下面所示的函数来模拟基于表达式的过滤功能:

'--------------------------------------------------------------------------
' ExpressionFilter
' 目的: 使用一个可以被VBScript计算的表达式,在一给定的列上过滤列表
' 输入: 指向电子表格和区域的引用,进行过滤的列号,和用来进行过滤得表达式。
' 输出:    无 (列表被过滤)
'
Sub ExpressionFilter(Spreadsheet, Range, ColumnNum, Expression)
    Dim sExp         ' 临时表达式变量
    Dim vValue       ' 临时存储变量
    
    Set c = Spreadsheet.Constants
    Set rngData = Range
    Set af = Spreadsheet.ActiveSheet.AutoFilter
 
    ' 启动一个撤销单元,以便将来可以作为一个完整单元的工作进行撤销。
    Spreadsheet.BeginUndo()
 
    ' 关闭ScreenUpdating属性开关,以便当重置过滤属性,排序和再次应用过滤    ' 时电子表格不会重画
    Spreadsheet.ScreenUpdating = False
    
    ' 清除任何现存的过滤设置
    ClearFilters Spreadsheet
 
    ' 获得指定列的过滤对象,并设置过滤功能属性为”包含”
    Set fltr = af.Filters(ColumnNum)
    fltr.Criteria.FilterFunction = c.ssFilterFunctionInclude
 
    ' 检查是否表达式包含了列值的替换符,
    ' 如果包含则设置标志
    fValueToken = cbool( _
        instr(1, Expression, g_sValueToken, vbTextCompare) > 0)
 
    '遍历各行中该列的值
    For Each cell In rngData.Columns(ColumnNum).Cells
        ' 获得当前单元的值
        vValue = cell.Value
        
        ' 如果vValue是一个字符串,为了防止其中包含了空格的情况
        ' 我们需要在它的前后加上引号
        If vartype(vValue) = vbString Then    
            vValue = """" & vValue & """"
        End If
        
        ' 组成我们需要执行的表达式,将当前行的值插入到表达式中
        ' 合适的位置处
        If fValueToken Then
            sExp = "g_fEval = cbool(" & Replace(Expression, _
                g_sValueToken, vValue, 1, -1, vbTextCompare) & ")"
        Else
            sExp = "g_fEval = cbool(" & vValue & " " & Expression & ")"
        End If
        
        ' 执行表达式
        window.execScript sExp, "VBScript"
        
        ' 全局变量g_fEval现在已经被设置成True或者False.
        ' 如果是True,该行将会被包含在过滤结果中.
        If g_fEval Then
            fltr.Criteria.Add cell.Text
        End If
    Next 'ct
 
    ' 最后执行自动过滤
    af.Apply
 
    ' 打开ScreenUpdating开关,使得电子表格可以重画
    Spreadsheet.ScreenUpdating = True
    
    ' 结束撤销单元
    Spreadsheet.EndUndo()
 
End Sub 'ExpressionFilter()

       上述函数使用文档对象模型(DOM)中名为execScript的方法执行表达式(DOM是为Internet Explorer中的脚本提供的编程模型)。这个方法将字符串形式的脚本代码传递给动态引擎脚本(在这个例子中,是VBScript)来计算。之后脚本代码将表达式的结果存储在一个全局变量中,以便结果能够被用来判断表达式的真假。如果表达式为真,该行将会被包含在过滤后的集合中;如果为假,该行将被排除。

       另外,您也可以使用电子表格组件的工作表对象中的Eval方法来计算表达式。Eval使用电子表格组件的函数库和表达式计算器,它可以代替动态脚本引擎,这就意味这在IE之外的容器中它会非常有用,另外当您希望可以让用户在表达式中使用电子表格的函数或区域的引用时它也会很有用。然而,动态脚本引擎可以提供一个强大的表达式计算器。还有,它允许您使用其它的脚本语言,例如ECMA脚本(也被称为JavaScript)。

装 载 数 据

       因为电子表格组件不是应用程序,所以关于”它从何处获得数据”和”如何保存它的数据”的问题就显得十分关键。但是,电子表格组件针对这些问题的答案比起应用程序针对这些问题的答案要复杂的多。不过好消息是电子表格组件可以通过各种方式加载和保存数据,您可以在解决方案中灵活的使用这些方式。

       与应用程序不同,组件不”拥有”容器所使用的存储设备。将这个窗体或文档保存到永久性的设备中,以及从永久性设备中重新装载的工作,都是容器的任务。容器通常会先要求组件将它当前的状态保存在一个流或属性包(property bag)中;然后将这些数据插入到正在保存的窗体或文档当中。正因如此,任何组件在方便的装载和保存数据时,都要不同程度的受到它所在的容器的支配。不必说,并不是所有的容器都一样;一些容器要比其它的容器出色。因为认识到这一点,在电子表格组件如何装载和保存数据方面,我们设计的很灵活。实际上,您可以通过4种方式将数据装载到电子表格控件中:

n         通过交互从Excel2000中发布一个电子表格或区域。

n         从Excel2000向电子表格控件中拷贝一个区域。

n         当电子表格控件位于设计器(例如Microsoft FrontPage 2000,Microsoft Script Editor,Microsoft Visual InterDev,以及Microsoft Visual Basic)中时,可以直接在控件中输入数据或一组新的公式。

n         指定一个URL来装载数据,这个URL会返回一个HTML文档,其中至少包含一个HTML表格。此外,也可以从一个URL处装载以逗号分隔的文本数据(CSV)。

从Excel中发布

       从Excel2000中通过交互的方式发布电子表格或区域,会提示Excel创建一个HTML文件,其中为电子表格组件包含了一个<object>的标签。Excel将所选择的电子表格或区域的内容拷贝到HTML页面文件中,作为<object>标签的一个参数,因此一旦数据被发布,它就不再引用原来的电子表格。然而,您可以方便地从Excel中重新发布内容,因为Excel会在页面文件中使用新的内容代替以前的内容,同时保留您对页面其它部分所作的修改。

       如果想要尝试一下从Excel2000中发布的功能,请打开您需要发布的工作薄,从”文件”菜单上选择”另存为Web页面…”的命令。您就会看到图2-4所示的对话框。

图2-4  选择”另存为Web页面”命令,来显示这个对话框

       选中”选择”这个选择项,并选择”添加交互”这个简化复选框。这样当您保存时,Excel就会生成一个包含了电子表格控件的页面,以及所选择内容的一个拷贝,而不是将内容保存为一个静态的HTML文件。如果需要对发布的内容进行更高级的控制,可以点击”发布”按钮,以显示”发布为Web页”的对话框。

       当试图将某些电子表格导入HTML中时,您可能会遇到错误信息。如果源电子表格是受口令保护的(通过使用工具|保护|保护工作表命令),Excel就不会允许将电子表格或任何区域发布到web页面中。因为web页面是纯文本的文件,任何人都可以在任何文本编辑器中打开,浏览和修改它,所以如果允许这样作的话,就会破坏安全性。当电子表格的作者需要防止用户修改某部分时,电子表格就会常常被密码保护。例如,Excel中的公司开支报告就常常被密码保护,以防止员工不能修改有效性验证规则的公式。

       请注意,您还是可以通过使用”保护”功能来锁定大多数的单元,以使用户只能修改那些您指定可以更新的单元。只要您不使用口令来保护电子表格,您就可以将电子表格发布或者拷贝到电子表格组件中,而且所有的保护设置都会被保留。

拷贝和粘贴

       Excel 2000和电子表格组件都会读写一种扩展的HTML表格格式的区域,这种格式在HTML上扩展了能够实现专门将信息导入到Excel中的功能的附加属性和XML(扩展标记语言)代码。这就意味着您可以从Excel2000中拷贝区域,并粘贴到电子表格控件中,或者反之,对于创建电子表格,和将电子表格控件中所看到的数据拷贝到Excel中以作进一步的分析的工作来说,这都是很有用的。

       当拷贝粘贴区域时,您应该注意一些问题。首先,如果区域中的一个元素包含一个公式,而这个公式引用了一个不在这个区域中的单元(在另一个工组表,或在另一个工作薄中),那么Excel会只拷贝该单元的当前值,而不会拷贝公式。让我们认真考虑这个问题:如果您将一个包含了拷贝区域外单元的引用的公式拷入电子表格控件中,那么电子表格控件就无法处理这个公式,因此也就不能显示任何数据。所以任何对拷贝区域外单元的引用都会被转换为与被拷贝时所引用的值相等的一个文本值。

       第二,Excel电子表格中更高级的结构,例如数据透视表,只会拷贝文本数据的单元,而不会拷贝数据透视表的结构(换句话说,粘贴后的数据不能再通过透视或钻取来获得更多的信息)。Office Web components是通过包含的数据透视组件来完成数据透视功能的。图表也根部不能被粘贴,因为电子表格组件不能寄宿其它的控件或浮动的图形。

       第三,电子表格的保护设置不仅影响内容如何被发布,还会影响内容怎样被粘贴到电子表格组件中。如果源电子表格是受密码保护的,那么区域还是能被拷贝粘贴,但是只有文本值会被粘贴到电子表格组件中。而如果电子表格是受保护的,但不是通过口令,那么区域会被正常拷贝。

       还要注意一件有趣的事,粘贴到电子表格组件中的格式是HTML,因此任何能够将HTML的表格拷贝到剪贴板中的应用程序也能被用来向电子表格组件中输入数据。虽然Excel2000确实在拷贝到剪贴板上的数据中嵌入了其它的信息,例如公式和一个给定单元的全精度值。但是,如果其它应用程序将不包含额外信息的HTML表格拷贝到剪贴板中,表格仍然会以附带格式的文本数据的形式粘贴到电子表格组件中。

直接在电子表格组件中输入

       关于这个方法,除了您会发现Excel中很多方便的创作电子表格的功能,在电子表格组件中已不存在之外,没有太多可说的。不过,您仍然可以在输入公式时通过选择单元来快速输入单元引用,通过属性工具箱来格式化信息,隐藏和显示标题栏、工具箱、列和行标头、以及表格线。在实际中,常常采用的方法是在Excel2000中建立您的电子表格,然后在完成后将内容发布和拷贝到电子表格组件中。不过如果是简单的电子表格,您可能会觉得在电子表格组件中只接输入模型更方便。

       之前提到过,不是所有的容器都可以在设计阶段方便的激活控件并进行交互的。只有在那些允许控件激活并能保存控件的内容的容器中,才能够实现直接在电子表格组件中录入的功能。

在Visual Basic和FrontPage中使用电子表格组件

       对于电子表格组件来说,Visual Basic和FrontPage都是非常优秀的容器;不过,一些技巧可以帮助您,使得编辑的过程更加轻松。

       在Visual Basic中,只要您单击电子表格组件,它就会被界面激活。这会使得很难在窗体中移动控件,因为单击和拖动操作的结果可以只是选择了一些单元的区域。不过,您可以通过单击标题栏并拖动来移动整个控件。如果标题栏不可见,可以通过设置DisplayTitleBar属性为true,来临时的显示它,然后再通过设置该属性为false来隐藏它。

       在Visual Basic或FrontPage中编辑电子表格组件时,您也应该避免使用AutoFit属性(将它设置为False)。在Visual Basic中使用AutoFit属性是危险的,因为在这种情况下,无论加载了什么内容到电子表格控件中,它都会调整大小来适应这些内容,以便不显示滚动条。如果内容比您的Visual Basic的窗体大的话,控件会立刻调整窗体边缘的大小。不过,如果您确定内容比窗体要小,并且控件绝不会获得比窗体大的内容,那么使用AutoFit还是安全的。

       在FrontPage2000中,正常视图下AutoFit属性不会起作用;不过,预览视图下,它可以在web浏览器中正确的工作。

从URL处装载数据

       对于将数据装载到电子表格组件中来说,URL是最奇怪,但也是最强大的机制。使用属性工具箱或编程模型,您可以让电子表格控件通过打开一个特定的URL,并加载在该URL处查找到的第一个HTML表格的方式来加载内容。CSV(以逗号间隔的文本)缺乏格式化或公式的信息,因此,您只能从CSV流中加载原始数据。数据是保留在URL所指的文件中的,电子表格控件会在每次初始化时加载这些数据。当然,这个URL可以方便地指向一个Microsoft的动态服务器页面(ASP)或者是一个CGI程序,这个页面或程序从企业数据库或其它的存储系统中动态的生成HTML表格,这样就使得您能够将动态,最新的数据加载到电子表格控件中。

       请注意电子表格组件使用IE中的安全机制来保证不会从除首页所在的域名之外的域名中加载数据 (根据您IE中的安全设置)。这个特性防止恶意的开发者向您发送一个包含了电子表格控件及在页面加载时就运行的脚本的web页面。如果安全特性设置的不合适,黑客就可以使用当前使用者的证书来加载敏感数据,并将数据发送至另一个地方,以供他(或她)详细查看。

这个特性使用客户端在IE中设置的安全设置,因此如果用户认为产生页面的站点是”可信的”,他们可以关闭跨域的访问警告。如果站点不在可信任的站点范围内,或者只设置了最低的安全设置,那么电子表格控件在从除首页所在的域名之外的任何域名访问一个URL之前,会警告用户。如果原始页面和加载时所在的URL位于同一个域名中,电子表格组件不会显示任何警告信息,因为这种情况被认为是安全的。

       我会在前面的章节中较多的讨论安全性。电子表格组件的安全机制与访问数据库时的安全机制(第五章将会更多的谈到)有一些不同:当URL指向的站点不在被信任的站点范围内时,它是不会允许用户有机会进行跨域访问的。这时电子表格控件仅仅返回一个错误值,并告诉用户该操作不被允许,然而在数据库访问的环境中,用户可以选择是否执行跨域访问。

       很遗憾,电子表格控件不能直接从一个二进制XLS文件中装载数据,但是它能如上面所述那样,从一个URL装载存为HTML格式的Excel文件。这就允许开发者使用Excel2000创建和维护一个电子表格模型。此外,还允许开发者在运行时直接将模型载入到电子表格控件中。

在同一个文件服务器上的不同共享是不同的域吗?

       在OWC产品开发周期接近尾声时,一个测试人员提交了一个关于电子表格组件的bug,说即使获得数据的URL和原始的HTML页面位于同一个文件服务器上时,组件也显示了一个安全警告消息。我们很困惑,因为这似乎确实应该是一个被信任的环境,不过因为我们使用IE的安全程序来决定是否两个URL是来自于同一个域,所以我们将BUG推给了IE小组。

       结果发现页面的URL和数据的URL确实指向同一个文件服务器,但是是指向那个文件服务器中不同的共享的。IE小组解释说,从技术上讲这确实是两个不同的域,因为在一个机构中使用一个巨大的文件服务器来为机构中不同的组织提供服务是很普通的事,而那些有访问某个共享权限的人,并不一定有访问另一个共享的权限。

       因此,如果您使用文件共享访问而不是web服务器,记住就安全性而言,同一个文件服务器上不同的共享被看作是不同的域。然而,这只适用于文件共享访问,而不适用于通过HTTP访问web服务器。

保存数据

       就象将数据装载到电子表格组件中,并不象在Excel应用程序中操作那么简单一样,从电子表格控件中保存数据可以以各种方式发生,这使得很难解释它。

       大多数容器不允许用户在运行状态下保存窗体或者文档。例如,一个Visual Basic窗体在运行时是没有直接的保存机制的。IE有一些不同:在显示页面时,它提供了一个”另存为”的机制,但是它不允许用户改变来自web服务器的原始页面。(如果允许这样的话,那么任何黑客就都能够修改您公司的主页了!) 我们常常遇到这种情况:当我们向客户展示Office Web Components时,他们最先闪现出的假设之一就是,他们能象使用一个共享文件一样,改变电子表格控件的内容,并将它重新保存到web服务器上。但是这是不可能的,因为Web的工作的原理不允许这样做――除非IE能够给web服务器返回一个新版本的页面,而绝大部分的服务器是根本不允许这样的。

       为了克服这些问题,我们开发了4种从电子表格控件保存数据的方法:

n         使用例如FrontPage2000这样的工具打开web页面进行编辑,完成修改并将页面保存到web服务器上。IE5在文件菜单上提供了一个新的”使用…编辑”命令,可以快速的将您浏览的页面载入到一个登记的HTML编辑器中。

n         使用电子表格控件的工具条上的”导出到Excel”按钮,快速的将它的内容导出到Excel2000中,在Excel200中您就可以将它存储为一个Excel工作薄或者将它以原始文件的方式发布到web服务器。

n         将电子表格控件的内容拷贝到剪贴板上,并将它粘贴到Excel2000中。

n         开发人员可以使用HTMLData属性来以文本流的形式获得当前内容,并在ASP页面或CGI程序中提交它,从而将它存储在服务器上。在第八章将会演示这个技术。