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

3
我有一个使用VSTO和Interop的Microsoft Word插件。如果已打开文档时触发DocumentOpen事件,我的代码会出现问题。我已经通过打开文档doc1,再打开另一个文档doc2,然后尝试再次打开doc1来一直重现这个问题。
显然,doc1已经打开,但是DocumentOpen事件再次为doc1触发。这是预期的设计吗?如果是,是否有简单的方法可以告诉我该事件是否是为已打开的文档而触发的?
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);
}

如果您打开Doc1,然后立即再次打开Doc1,它是否会触发?如果您编辑Doc1一点点,不保存,然后再次打开Doc1呢? - user798182
奇怪..我猜是因为你打开它的线程/进程的原因吗?抱歉,我无能为力。 - user798182
1个回答

5
据我阅读文档和进行一些实证研究,似乎DocumentOpen事件在以下情况下会被触发:
  • 您先打开doc1,然后打开doc2,再次打开doc1

但是,如果您:

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

因此,规则可能类似于:“如果您反复打开同一文档,则事件仅触发一次。但是,当您打开与最近打开的文档不同的文档时,无论该文档是否已在运行中的Word实例中打开,事件都将为新打开的文档触发。”

我一直在文档中寻找更多关于此事的详细信息,但没有任何收获。但是,如果您真的想知道发生了什么,我建议您在MSDN论坛上提出问题,那里的一些MVP可能能够帮助您。

然后您问:

有没有简单的方法可以告诉我事件是否针对已经打开的文档而触发?

是的,我认为 :)

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

为了说明这一点,我构建了一个使用 Word Interop 实现此操作的示例 - 就我所知,这几乎可以与 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!");
            }
        }
    }
}

希望这有所帮助! :)

我已经在跟踪打开的文档,所以这个很好用。但我仍然很好奇为什么“OpenDocument”事件会被多次触发。 - Joe W
我很高兴提议的解决方案起作用了 :) 我同意你的观点,知道OpenDocument实际上应该如何工作会很好。 - Lasse Christiansen
抱歉回复晚了,但是我想提醒一下关于 DocumentBeforeClose 的问题。当文档未保存(因此 Saved 属性设置为 False)时,它会提示用户是否保存文件。可能用户选择取消选项,然后文档仍然保持打开状态,但是 DocumentBeforeClose 事件已经触发!所以请小心! - etaiso

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接