【问题标题】:Creating and managing custom task panes for multiple documents in a VSTO Word addin在 VSTO Word 插件中为多个文档创建和管理自定义任务窗格
【发布时间】:2018-05-05 00:20:53
【问题描述】:

我正在使用 Visual Studio 2008 中的 VSTO 开发 Word 2007-2010 插件。在我的插件中,我需要为每个打开的 Word 文档创建一个自定义任务窗格。基本上,我需要为每个文档创建一个任务窗格,在文档窗口中显示正确的任务窗格,在文档关闭时执行一些操作,然后删除任务窗格以及对它的所有引用。

这是我到目前为止所做的:

创建任务窗格

我为每个新的、打开的或现有的加载文档创建一个自定义任务窗格,如下所示:

((ApplicationEvents4_Event) Application).NewDocument += CreateTaskPaneWrapper;
Application.DocumentOpen += CreateTaskPaneWrapper;
foreach (Document document in Application.Documents)
{
    CreateTaskPaneWrapper(document);
}

在 CreateTaskPaneWrapper 方法中,如果文档的任务窗格已经存在,我会检查 Dictionary。我这样做是因为如果我尝试打开一个已经打开的文档,则会触发 open 事件。如果它不存在,我创建一个新的 TaskPaneWrapper 类。在其构造函数中,我创建了一个新的任务窗格并将其添加到 CustomTaskPanes 集合中

Globals.ThisAddIn.CustomTaskPanes.Add(taskPane, "Title");

According to MSDN,这会将任务窗格与当前活动窗口相关联。

任务窗格关闭

Document.Close 和 Application.DocumentBeforeClose 事件都不适合我,因为它们在用户确认关闭文档之前触发。所以我在我的 TaskPaneWrapper 类中使用 Microsoft.Office.Tools.Word.Document.Shutdown 事件,如下所示:

_vstoDocument = document.GetVstoObject();
_vstoDocument.Shutdown += OnShutdown;

private void OnShutdown(object sender, EventArgs eventArgs)
{
    Globals.ThisAddIn.CustomTaskPanes.Remove(_taskPane);
    //additional shutdown logic
}

所有这些似乎都工作得很好,任务窗格被创建,绑定到相应的窗口,并被成功删除。但是,我仍然有一个问题 - 当我启动 Word 时,会打开一个空白文档。如果我随后打开现有文档而不更改空白文档,则会删除空白文档及其窗口,而不会触发 Document.Close、Application.DocumentBeforeClose 和 Microsoft.Office.Tools.Word.Document.Shutdown 事件。因为没有调用 OnShutdown 并且没有删除空白文档的任务窗格,所以下一个文档窗口包含两个任务窗格 - 非常新的一个和第一个(孤立的)一个。如何删除这个孤立的任务窗格?访问已删除的文档或窗口引用会引发 COMException(“对象已删除”)。我暂时使用这个 hack:

//A property in my TaskPaneWrapper class
public bool IsWindowAlive()
{
    try
    {
        var window = _vstoDocument.ActiveWindow;
        return true;
    }
    catch (COMException)
    {
        return false;
    }
}

在 CreateTaskPaneWrapper 方法中,我检查所有现有包装器的此属性并关闭属性为 false 的包装器。当然,捕捉异常有点昂贵,而且这个解决方案非常hacky,所以我想知道,有没有更好的解决方案? In this question CustomTaskPane.Window 属性被检查为 null,但它从不为我返回 null。

另外,使用我当前的逻辑还有其他问题吗?为多个文档管理多个任务窗格的典型方法是什么?

【问题讨论】:

  • +1 将我指向 Document.Shutdown 事件 :-)

标签: ms-word vsto add-in office-interop customtaskpane


【解决方案1】:

这篇题为Managing Task Panes in Multiple Word and InfoPath Documents的MSDN文章详细介绍了这个问题

您必须创建一个方法来删除孤立的 CTP(即那些不再附加窗口的 CTP)。

我已经按照这篇文章成功实现了一个 CustomTaskPane 管理器来移除孤儿。

【讨论】:

  • 感谢链接,我不记得读过这篇文章了。我现在已经转到另一个项目,所以我对细节有点模糊,但是文章建议检查自定义任务窗格的窗口是否为空,这对我不起作用,正如我在问题中提到的.我刚刚签入 Word 2010,它从不返回 null,即使任务窗格是孤立的。
  • Matt - 不知何故,在某个地方,我找到了指向您的“CustomTaskPane 管理器”的链接,但我终其一生都找不到了。这还能用吗?谢谢!
【解决方案2】:

这个答案在MSDN

您可以通过在调用 CreateTaskPaneWrapper 之前从 DocumentOpen 事件处理程序中调用以下方法来主动清理,而不是在打开现有文档后被动地清理孤立的任务窗格。此代码循环通过属于加载项的每个自定义任务窗格。如果任务窗格没有关联的窗口,则代码会从集合中删除任务窗格。

private void RemoveOrphanedTaskPanes()
{
    for (int i = Globals.ThisAddIn.CustomTaskPanes.Count; i > 0; i--)
    {
        CustomTaskPanes ctp = Globals.ThisAddIn.CustomTaskPanes[i - 1];
        if (ctp.Window == null)
        {
            this.CustomTaskPanes.Remove(ctp);
        }
    }
}

private void Application_DocumentOpen(Word.Document Doc)
{
    RemoveOrphanedTaskPanes();
    CreateTaskPaneWrapper(document);
}

【讨论】:

    【解决方案3】:

    尝试一些事情::

    1. 也许您可以在 DocumentNew- 和 DocumentOpen-Event 中检查“Word.Application.Documents.Count”以跟踪实际打开的文档。

    2. 要查明文档是否已打开(可能与重新打开活动文档相关),您可以使用打开文档的字典。密钥可以是唯一的文档名称。

    3. 您可以按如下方式捕获 Disposed-Event,而不是您的 IsWindowAlive() 方法

    _vstoDocument.Disposed += _vstoDocument_Disposed;
    
            void _vstoDocument_Disposed(object sender, EventArgs e)
            {
                //Remove from dictionary of open documents 
            }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-11-01
      • 1970-01-01
      相关资源
      最近更新 更多