zoukankan      html  css  js  c++  java
  • 探索 Word 2007 开发(三):管理侧栏

    探索 Word 2007 开发(三):管理侧栏

    Written by Allen Lee

    问题再现

            我在上一回提到了"我的博客"侧边栏的一个问题,现在来看看到底是什么回事。首先,依次打开《探索Word 2007开发(一):我的博客》和《探索Word 2007开发(一):扩展Ribbon》两篇文章;然后,点击任意一篇文章上的My Blogs按钮。有趣的事情发生了,两篇文章上的My Blogs按钮都处于按下状态,却只有《探索Word 2007开发(一):我的博客》上出现"我的博客"侧边栏:

    Figure 1

            对于这个问题,Andrew Whitechapel在《The Anomalous Behavior of Custom Task Panes in Word and InfoPath》里做了解释,而Robert Green也在《Managing Task Panes in Multiple Word and InfoPath Documents》里提出一种解决方案,然而,我希望"我的博客"侧边栏具有Research侧边栏那样的效果,而不是按照Robert的方案来实现的效果。如果你不知道Research侧边栏具有怎样一种效果,我强烈建议你先去体验一番,具体的步骤可以在Robert的文章里找到。

    管理侧栏

            我曾不止一次同时查看多个打开的Excel窗口,一不小心关闭其中一个致使其它的都关闭了,然而,这种情况不会出现在使用Word的时候。究其原因,乃Andrew和Robert在他们各自的文章里讲述的,Word和Excel使用了不同的窗口模型。

            还记得我们是怎样把"我的博客"侧边栏添加进Word窗口的吗?我们是在ThisAddIn_Startup() 方法中使用CustomTaskPaneCollection.Add() 方法把它添加进来的:

            细心的你可能已经发现,我们并没有在这里为"我的博客"侧边栏指定父窗口,VSTO将会把它添加进当前窗口。如果这用在Excel,由于各个Excel窗口共享同一个"Document Frame Window",那么每个打开的Excel窗口也将共享这个"我的博客"侧边栏。但若这用在Word,情况将大不相同,第一个启动的Word窗口将独享"我的博客"侧边栏,其它的都无福消受了。怎么解决这个问题?

            一种办法就是处理Microsoft.Office.Interop.Word.Application对象的NewDocument和DocumentOpen事件,使用CustomTaskPaneCollection.Add() 方法的重载版本为每个新建或打开的窗口添加"我的博客"侧边栏。当用户关闭窗口时,我们应该销毁与之关联的侧边栏,然而,正如Robert的文章所指出的,Word没有提供DocumentClosed事件,如果我们在DocumentBeforeClose事件的Event Handler里销毁侧边栏,那么当用户取消关闭窗口时,就会发现侧边栏已被莫名其妙地关闭了,这显然是不可接受的。对于这个问题,Robert的方法确实是一个不错的选择。值得提醒的是,如果添加侧边栏的代码只存在于NewDocument和DocumentOpen事件的Event Handler中,那么第一个新建或者打开的窗口都不会有侧边栏,因为这两个事件是在第一个窗口之后才触发的,于是,你需要把代码复制一份放在ThisAddIn_Startup() 方法里面。

    增值服务区

            另一种办法就是,当用户点击My Blogs按钮时判断当前窗口是否有与之关联的侧边栏,有则显示,无则创建并显示。而侧边栏的销毁则与上一种办法相同。

            接下来,我将采用第二种办法来管理"我的博客"侧边栏,稍稍不同的是,我会把侧边栏的创建/获取和销毁等工作外包给MyBlogsPaneManager类而不是直接放在相关的Event Handler里。

    // Code #02

    MyBlogsPaneManager

             对于Code #02,以下几点是需要说明的:

    • GetMyBlogsPane() 方法会判断是否存在标题为"My Blogs"、父窗口为当前窗口的侧边栏,有则返回,无则创建。不难看出,该方法总是返回与当前窗口关联的侧边栏。
    • CollectMyBlogsPanes() 方法负责回收废弃的侧边栏。

    考验脑力区

    • CollectMyBlogsPanes() 方法里的递减for循环可以改为递增for循环或者foreach吗?

            之前我们在ThisAddIn类里面处理侧边栏的添加和相关事件,现在需要把这些代码迁移到BloggingRibbon类里。

            首先,把MyBlogsPaneVisibleChanged() 从ThisAddIn类移到BloggingRibbon类,并做适当调整:

            接着,修改MyBlogs按钮的Click事件的Event Handler:

            然后,在ThisAddIn类里面处理Microsoft.Office.Interop.Word.Application.DocumentChange事件:

            以及在InternalStartup() 方法里添加如下这行代码:

    this.Application.DocumentChange += new Word.ApplicationEvents4_DocumentChangeEventHandler(DocumentChange);

            最后,就是删除废弃/多余的代码了。然而,现在的插件处于一个中间状态,它不完整,如果运行的话将会出现一些古怪的行为,接下来将会分析并解决这个问题。

    同步状态

            细心观察Figure 1,你会发现,两个窗口的My Blogs按钮都处于按下状态,起初我以为这是因为它们都关联到同一个侧边栏,而此时这个侧边栏又处于显示状态,因此它们同时处于按下状态就不足为奇了。然而,事情却不是这么简单,我创建一个单独的插件项目观察多个窗口中按钮的状态,发现如下两个事实:

    • 这些按钮的按下/释放状态是共享的。当我按下其中一个窗口的My Blogs按钮并激活其它窗口时,被激活窗口的My Blogs按钮也会变成按下状态。
    • 这些按钮的状态同步并非立即发生的。当我按下其中一个窗口的My Blogs按钮但保持当前窗口的活动状态,其它窗口的My Blogs按钮仍然保持释放状态。

            不难看出,我们可以在Microsoft.Office.Interop.Word.Application.WindowActivate事件的Event Handler里做一些手脚:

            当然,你必须在InternalStartup() 方法里面把它关联该事件:

    this.Application.WindowActivate += new Word.ApplicationEvents4_WindowActivateEventHandler(WindowActivate);

            现在,我们来看看运行效果:

    Figure 2

    Figure 3

            如果你来回切换Figure 2的两个窗口,你会发现My Blogs按钮在每次切换时都会"闪动",这种"闪动"其实是使用WindowActivate事件修正My Blogs按钮状态的一个小小的副作用。细心的读者可能会发现,Word自带的Research侧边栏在同样的情况下也会"闪动"。

            至此,侧栏问题的探讨要告一段落了。此时,有人可能会问,Word 2007在兼容MetaWeblog API上有问题,致使我们无法使用它在博客园发布带图片的文章,那么为什么我还要花费这么多精力来对它进行扩展呢?正如很多人所知道的,这个问题是由Word 2007的一个bug所致的,坊间也流传一些有效的解决办法,这恰恰说明了大家不愿放弃Word这个强大的编辑工具。下一回,我将会从Word 2007的扩展特性入手,探讨另一种可能的解决办法。

  • 相关阅读:
    LeetCode 264. Ugly Number II
    LeetCode 231. Power of Two
    LeetCode 263. Ugly Number
    LeetCode 136. Single Number
    LeetCode 69. Sqrt(x)
    LeetCode 66. Plus One
    LeetCode 70. Climbing Stairs
    LeetCode 628. Maximum Product of Three Numbers
    Leetcode 13. Roman to Integer
    大二暑假周进度报告03
  • 原文地址:https://www.cnblogs.com/allenlooplee/p/907131.html
Copyright © 2011-2022 走看看