在 VSTO Word 插件中为多个文档创建和管理自定义任务窗格 [英] Creating and managing custom task panes for multiple documents in a VSTO Word addin

查看:35
本文介绍了在 VSTO Word 插件中为多个文档创建和管理自定义任务窗格的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm developing a Word 2007-2010 addin using VSTO in Visual Studio 2008. In my addin, I need a custom task pane for each open word document. Basically, I need to create a task pane for each document, show the correct task pane in the document window, do something on document close and then remove the task pane and all references to it.

这是我目前所做的:

任务窗格创建

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

I create a custom task pane for each new, opened or existing on load document like this:

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

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

In the CreateTaskPaneWrapper method, I check a Dictionary<Document, TaskPaneWrapper> if a task pane for a document already exists. I do this because the open event fires if I try to open an already open document. If it doesn't exist, I create a new TaskPaneWrapper class. In its constructor, I create a new task pane and add it to the CustomTaskPanes collection with

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

根据 MSDN,这会将任务窗格与当前活动的窗口相关联.

According to MSDN, this associates the task pane with the currently active window.

任务窗格关闭

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

Both Document.Close and Application.DocumentBeforeClose events don't suit me, because they fire before before the user gives the confirmation to close the document. So I use the Microsoft.Office.Tools.Word.Document.Shutdown event in my TaskPaneWrapper class like this:

_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:

All of this seems to work pretty well, the task panes are created, bound to the corresponding windows, and are successfully removed. However, I still have one problem - when I start Word, a blank document opens. If I then open an existing document without changing the blank one, the blank document and it's window is deleted without the Document.Close, Application.DocumentBeforeClose and Microsoft.Office.Tools.Word.Document.Shutdown events firing. Because OnShutdown is not called and the task pane for the blank document is not deleted, the next document window contains TWO task panes - the very new one, and the very first (orphaned) one. How can I remove this orphaned task pane? Accessing the deleted document or window reference throws a COMException ("Object was deleted"). I'm temporary using this hack:

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

在 CreateTaskPaneWrapper 方法中,我检查所有现有包装器的此属性并关闭属性为 false 的那些.当然,捕获异常有点昂贵,而且这个解决方案非常笨拙,所以我想知道,有没有更好的解决方案?在这个问题中 CustomTaskPane.Window 属性被检查为 null,但它永远不会为我返回 null.

In the CreateTaskPaneWrapper method, I check this property for all existing wrappers and shutdown the ones where the property is false. Catching an exception is somewhat expensive, of course, and this solution is pretty hacky, so I was wondering, is there a better one? In this question CustomTaskPane.Window property is checked for null, but it never returns null for me.

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

Also, are there any other problems I can run into using my current logic? What's the typical way of managing multiple task panes for multiple documents?

推荐答案

MSDN

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

Instead of reactively cleaning up orphaned task panes after you open an existing document, you can proactively clean up by calling the following method from the DocumentOpen event handler before you call CreateTaskPaneWrapper. This code loops through each of the custom task panes that belong to the add-in. If the task pane has no associated window, the code removes the task pane from the collection.

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);
}

这篇关于在 VSTO Word 插件中为多个文档创建和管理自定义任务窗格的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆