下面,我们来看看插件的实现,首先,参考《探索 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事件委托里完成: