实战OBA VSTO+WSS
最近帮朋友忙,用Visual Studio Tools for Office 3.0 + Word2007 + Windows Sharepoint Service实现了一个B/S的Office应用,觉得有必要跟大家分享一下心得。呵呵。
先讲一下需求:
需求是这样的,客户想要构建一个基于Word的信息管理系统。
具体要求如下:
1. 1. 能把Word文档里的指定内容保存到数据库中
2. 2. 能随时调取这些保存在数据库中的内容到Word中而编辑成为一份新的文档。
3. 3. 希望Word文档带有版本管理的功能。
分析:
需求其实很简单,但做起来就有很多的问题了。笔者遇到的问题如下:
1. Word文档是非结构化的,而数据库是结构化的,如何映射?
2. Word文档内容的种类是多种多样的,包括图片,Word公式,各种图标,线段等等,如何保存?同时又如何保证上述各种类型的数据保存到数据库中是可“反序列化”的,就是说再从数据库中读出来,放到Word中,还和原来的内容一样(公式还是公式,还可以对公式进行编辑)?
3. 版本管理可以使用MOSS或WSS,但如何与VSTO结合
上述这些问题都比较棘手,笔者曾经想过几种方案:
1. 使用OpenXML + Content Control。因为OpenXML是结构化的,并且Content Control可以绑定到自定义的数据。但这种方案又很快被否定了,因为OpenXML的操作不具交互性,不能在打开Word文档的同时进行数据操作。
2. 使用VSTO + Content Control。VSTO可以方便的对Word进行无缝扩展,方便地操作Word文档。也可以用Content Control进行数据绑定。
大体方案定了之后,就开始对每一个技术难点进行攻关,找到解决方案:
1. 如何把非结构化的文档内容保存到结构化的数据库中。
a. 其实这个问题就是如何对Word文档内容进行结构化的划分,使指定的内容可以映射到数据库的一条记录。最好的方式当然是使用Content Control。因为它可以包括任何的Word内容,而且也可以嵌套,当然是天然的结构化“利器”。并且只要管理好Content Control的命名,即可保存多种内容到数据库中。
2. 如何把各种类型的内容“序列化”到数据库中但又能“反序列化”到Word中。
这个问题就比较棘手了,要研究Word的内容格式。大家都知道Word采用的是RTF的复文档格式。但如何把RTF格式的内容“序列化”呢?在没有深入研究之前,笔者第一个想法是使用流保存到数据库的二进制字段中。
但事情没那么简单,在笔者研究如何把RTF格式内容转换成流的过程中,发现另一个问题。
如何得到RTF格式的内容
这个问题看起来很简单,有人想,用鼠标选中不就行了吗?其实不然,大家可以去试试,在Word中输入一段文字,再画一条线,或者一个矩形,然后选中试试。这两种内容是不能被同时选中的。
有人又说,用VSTO中的Word Object Model的Range或者Selection对象选中也可以,笔者虽然没尝试,但觉得也跟用鼠标的情况类似。
为此,笔者想到了一个办法,就是使用Content Control。在尝试中,笔者发现Content Control是可以包含任何Word内容的,不管是文字,图片,图形,公式等,都可以包含进来。不过对于刚才提到的线段和矩形,就不能“复制”到Content Control中,但可以拖动到Content Control中,这样Content Control也能自动包含它们。下面是一个图示:
上图中带箭头的线就是我手动拖到Content Control中去的。
RTF内容是包含到Content Control中了,但是如何得到呢,如何“原封不动”地转换成流,这个问题困扰了笔者一段时间。
经过研究,笔者发现了一条“捷径”,可以绕过很多这些麻烦的问题。就是使用“剪贴板”。剪贴板是Windows的基础功能,所有的Windows都支持,VSTO当然也不例外。笔者就发现了VSTO中Range对象的Copy()方法,可以直接把Range中的内容拷贝到剪贴板中。由于Word也是使用剪贴板来复制/粘贴,所以这样Word内容的RTF格式就不会丢失了。于是笔者使用了Content Control.Range.Copy()方法,把Content Control中的所有内容(包括图标,线段等)复制到剪贴板中。
现在内容是复制到剪贴板中了,下一步就是从剪贴板中取出来。
由于剪贴板中存放的内容格式有很多,所以首先要找出Word内容存储在剪贴板的格式类型。经过笔者研究,Range.Copy()方法把内容用RTF格式复制到剪贴板。所以得到内容的方式就很简单了。使用:
object obj = Clipboard.GetData(System.Windows.Forms.DataFormats.Rtf);
将得到的内容保存到数据库中
得到剪贴板中的内容,笔者监视得到的object,发现原来根本就是一个被“序列化”的字符串。所以,保存此字符串到数据库中就OK了(当然也可以使用流存到二进制字段中)。
取出保存的内容,添加到Word中
至于“反序列化”的过程,使用:Clipboard.SetData(System.Windows.Forms.DataFormats.Rtf, content);
Control Control.Range.Paste();
即可,任何格式的内容都不会丢失。
3. 如何把VSTO与WSS结合
所谓的VSTO与WSS结合,其实就是WSS文档库中的文档都具备我们用VSTO开发好的这些功能。
这个问题不复杂。只需要做几个步骤。
a. 发布VSTO
b. 创建WSS文档库
c. 在WSS中新建一个内容类型
d. 将新建的内容类型与我们发布的VSTO关联
e. 将新建的内容类型添加到文档库中
这样就客户可以在WSS的文档库中新建并打开文档了,第一次新建文档时,会自动安装我们的VSTO 扩展到客户的机器上,就可以使用我们的自定义功能了。
具体结合方法参见:http://exchange.ctocio.com.cn/office/89/8171589.shtml
下面是一个简单的例子,说明如何添加Content Control并复制和粘贴。
至此,我们的实战OBA项目就结束了。希望笔者的经历能在大家的OBA开发上有所帮助。