为什么 Microsoft Word 会为已打开的文档触发 DocumentOpen 事件

Joe*_*e W 3 c# vsto add-in office-interop

我有一个使用 VSTO 和互操作的 Microsoft Word 插件。如果DocumentOpen为已经打开的文档触发事件,我的代码就会出现问题。我已经能够通过打开文档 doc1、打开另一个文档 doc2,然后再次尝试打开 doc1 来一致地复制这一点。

Doc1 显然已经打开,但再次为 doc1 触发 DocumentOpen 事件。这是一个预期的设计,如果是,是否有一种简单的方法可以判断是否正在为已打开的文档触发事件?

private void ThisAddIn_Startup(object sender, System.EventArgs a)
{
  try
  {
    this.Application.DocumentOpen += 
      new MSWord.ApplicationEvents4_DocumentOpenEventHandler(Application_DocumentOpen);

  }
}

private void Application_DocumentOpen(MSWord.Document document)
{
  HandleOpenedDocument(document);
}
Run Code Online (Sandbox Code Playgroud)

Las*_*sen 5

据我通过阅读文档并进行一些实证研究可以看出,DocumentOpen如果出现以下情况,该事件似乎会被触发:

  • 你打开 doc1,然后是 doc2,然后又是 doc1

但是,如果您:

  • 打开 doc1 然后再次打开 doc1,该事件仅在第一次打开 doc1 时触发。

所以规则可能是这样的:“如果你一遍又一遍地打开同一个文档,事件只会被触发一次,但是,当你打开一个与最近打开的文档不同的文档时,事件会被新打开的文档触发无论该文档是否已在正在运行的 Word 实例中打开。”

我一直在文档中寻找更多细节,但没有任何运气。但是,如果您真的想知道发生了什么,我建议您在 MSDN 论坛上提问,其中一些 MVP 可能会提供帮助。

那你问:

有没有一种简单的方法可以判断是否为已经打开的文档触发了事件?

是的,我想:)

基本上,您可以在应用程序中保留一组打开的文档,并使用DocumentOpenDocumentBeforeClose事件来维护该集合。知道当前打开了哪些文档,在触发事件时确定文档是否已经打开变得很简单 - 只需在集合中查找即可。

为了说明这一点,我构建了一个示例实现,说明如何使用 Word Interop 完成此操作——据我所知,这应该几乎 1 比 1 映射到 VSTO。我在代码中提供了一些注释,因此应该很容易理解发生了什么。

using Microsoft.Office.Interop.Word;
using Application = Microsoft.Office.Interop.Word.Application;

namespace WordDocStats
{
    internal class Program
    {
        private static readonly HashSet<Document> OpenDocuments = new HashSet<Document>();

        private static void Main()
        {
            var wordApplication = new Application() { Visible = true };

            // Listen for documents open
            wordApplication.DocumentOpen += WordApplicationDocumentOpen;

            // Listen for documents close
            wordApplication.DocumentBeforeClose += WordApplicationDocumentBeforeClose;

            Console.ReadLine();
            wordApplication.Quit();
        }

        static void WordApplicationDocumentBeforeClose(Document doc, ref bool cancel)
        {
            OpenDocuments.Remove(doc);
            Console.WriteLine(doc.Name + " closed!");
        }

        static void WordApplicationDocumentOpen(Document doc)
        {
            // If this returns true, the doc is not in the set of open documents, hence the doc is not already open
            if(OpenDocuments.Add(doc))
            {
                OpenDocuments.Add(doc);
                Console.WriteLine(doc.Name + " opened...");
            }
            // Otherwise, the doc is already in the set of open documents, hence we know the document is already open
            else
            {
                Console.WriteLine(doc.Name + " is already open!");
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助!:)