首页 > 单独文章 > 正文

引用.NET Framework Class Library 在线文档1——Word 2007高级应

时间:2008-02-13 12:12:45 作者:officeba 【认证】

前言   每当我在文章中提到.NET Framework的某个类、属性或者方法时,我会为它添加一个超链接,引用.NET Framework Class Library的在线文档。首先,我用浏览器打开MSDN Library的页面,接着,在左边的导航目录树中定位到对应的节点,然后,把该节点的超链接复制下来,最后回到Word2007中插入这个超链接。然而,我已经对这个繁琐的过程感到厌倦了,是否有办法把.NET Framework Class Library的在线文档集成到Word 2007中,从而让这个过程变得更加简单呢?


需求 X 需求

下图是用Paint.NET弄出来的示意图:

 

图   1

我希望把MSDN Library上.NET Framework Class Library那部分导航目录树以侧边栏的方式集成到Word 2007里,这样,当我右击某个节点,点击Insert菜单项时,将在当前文档的光标处插入该节点对应的连接。

作为用户,我提出了上面这些需求,那么,作为开发人员,为了实现这项功能,我又该提出哪些"需求"呢?

首先,我需要MSDN提供访问这些数据的服务,没有这个服务,实现这项功能就非常困难,甚至变得不可能。幸亏,MSDN的确提供了这样一个服务,它叫MTPS(MSDN/TechNet Publishing System)Content Service(以下简称"MPTS")。这样,实现这项功能的首要任务就是学习使用这个服务了。这里将会用到Craig Andera在其文章上所提到的知识和技巧(见下表)。
其次,我需要知道如何为Word 2007创建侧边栏以及为这个插件在Ribbon上添加一个启动按钮。这里将会用到《探索 Word 2007 开发(一):我的博客》、《探索 Word 2007 开发(三):管理侧栏》和《探索 Word 2007 开发(二):扩展 Ribbon》三篇文章的研究成果。
再次,我需要知道TreeView这个控件的使用方法和技巧。这里将会用到《TreeView 四技》这篇文章的研究成果。
最后,我需要知道如何在Word 2007中插入超链接。

 

多重影分身术

多重影分身术是一种实体复制忍术,如果你看过《火影忍者》,应该能够理解它的意思。现在我要做的和这个差不多,为MSDN Library的.NET Framework Class Library导航目录树产生出多个实体分身,并把它们嵌入Word 2007里,不同的是,多重影分身术是由本体实施,而这里的实体复制是由身为第三方的我来实施。

本节的焦点是用MTPS返回的数据填充侧边栏里的TreeView控件。下面是这个插件的需求列表:

一开始,TreeView里面只有一个顶节点——.NET Framework Class Library,且该节点是折叠的。
使用延迟填充技术,每个可展开节点会且只会在第一次展开时访问MTPS获取数据,并填充子节点。
这两个需求看起来很简单,然而,一旦和MTPS 结合使用就比较复杂了,你需要区分MPTS所使用的两套标识系统,一套是用于标识节点的导航的,另一套是用于标识节点所指向的内容的。如果你还没接触过MTPS,那么我强烈建议你先阅读Craig Andera的两篇文章,否则你有可能无法理解后面的内容。这里我做一个简单的介绍,MTPS有两种节点:导航节点和内容节点,导航节点与MSDN Library/TechNet Library左侧的导航目录树中的节点一一对应;内容节点则是与该导航节点对应的用于显示在右侧的内容。这两种节点使用了同一种标识模型,每一个标识包含了三个部分:标识符、区域信息和版本信息。其中标识符又分五种类型:short ID、content alias、content GUID、content URL和asset ID。并非所有节点都同时具备这五种标识符,也并非所有情况下MTPS都返回/接受这五种标识符,于是,如果你需要在不同的标识符之间切换,你可能需要再次访问MTPS。有鉴于此,上述两个需求的复杂性主要体现在处理不同种类的节点以及用于标识这些节点的不同种类的标识符上。

下面,我们来看看插件的实现,首先,参考《探索 Word 2007 开发(一):我的博客》这篇文章里提到的方法在Visual Studio 2008 Beta 2中创建一个项目骨架,里面包含一个空白的Ribbon(取名ReflinksRibbon)和一个空白的User Control(取名TocView),并在TocView上放置一个TreeView控件:

 

图   2

我不打算用普通的TreeNode来填充这个TreeView,而是使用根据MTPS的节点模型创建的自定义节点类来填充,当然,这个自定义节点类继承自TreeNode类:

 

Code 1

TOC全称Table of Content,TocNode与MTPS的TOC导航节点模型向对应:

TocNode.Text:节点标签(Label),对应于toc:Title;
TocNode.Target:与该导航节点对应的内容节点的标识符,对应于toc:Target;
TocNode.Locale:与该导航节点对应的内容节点的区域信息,例如zh-CN,对应于toc:TargetLocale;
TocNode.Version:与该导航节点对应的内容节点的版本信息,例如VS.90,对应于toc:TargetVersion;
TocNode.SubTree:如果该导航节点包含子节点,则该属性为子节点树片断的标识符,对应于toc:SubTree。
我希望使用《TreeView 四技》这篇文章里提到的延迟填充技巧,并让节点自行负责子节点的填充,如果某个节点拥有子节点,它也必须负责通知TreeView对其做出适当的渲染。下面是通过MTPS获取当前节点的子节点(注意,MTPS仅返回下一级的子节点):

 

Code 2

我们可以通过检查SubTree是否为null知道当前节点有否子节点,然而,我们还是无从得知子节点的装载是否已经执行过。重复装载无疑导致不必要的网络访问,于是,我为TocNode添加了一个类型为bool的m_Loaded字段。这样,仅当SubTree不为null以及m_Loaded不为false时,我们才装载子节点。所有这些操作都是在用户点击节点前面那个+号时才执行的,但由于子节点还没填充,TreeView是不会为该节点渲染+ 号的,于是,我们需要为该节点添加一个"占位子节点",以便TreeView能够正确渲染。添加占位子节点的最佳时机是当我们给SubTree属性赋值时,所以我把SubTree属性修改如下:

 

Code 3

有了这些准备,我们就可以实现Load()方法来装载子节点了:

 

Code 4

这个方法将会在TreeView的BeforeExpand事件委托里调用:

 

Code 5

值得提醒的是,当子节点填充完毕后,别忘了删除之前加入的占位子节点,并把m_Loaded的值设为true。另外,这里使用了GetAttribute()辅助方法来获取XAttribute的值:

 

Code 6

这样,TreeView的填充就变成简单地添加一个根节点了,这将在TocView的Load事件委托里完成:

 

Code 7

好了,现在来看看效果:

 

图   3

噢,TreeView的位置有问题!这个问题可以通过设置TreeView的Anchor属性以及TocView的Dock属性解决。我们知道,控件的Anchor属性的默认值为Top和Left的组合,然而,我们并不希望TreeView的右边和下边留下这么多空白,这样就可以把它的值设为Top、Left、Right和Bottom的组合。或者你认为把TreeView的Dock属性的值设为Fill更省事,但我还是喜欢四周留有一些"余地",至于留空多少,你可以通过Margin属性指定。而TocView的Dock属性可以在添加侧边栏时设置:

 

Code 8

现在,重新编译并运行,看看效果如何:

 

图   4

嗯,这次就好多了。

 

(未完,待续)


相关文章

同类最新