在新工作簿中,Excel中的CustomTaskPane不会出现

13

我已经将一个CustomTaskPane添加到Excel 2013中,让用户可以快速搜索照片。如果用户只打开/创建一个工作簿,它能够正常地工作。问题是,如果他们打开另一个工作簿或创建一个新的工作簿,该任务窗格不会出现在新窗口中。它仍然停留在原始窗口中。我知道这种行为是由于我只在打开Excel时初始化了面板。我添加了一个事件处理程序到ActiveWindow事件,以在打开另一个工作簿时初始化一个新面板。

问题是,我无法判断CustomTaskPane是否已经存在于窗口中。如果存在,则会简单地创建另一个CustomTaskPane,因此该窗口中现在有两个CustomTaskPane。我编写了以下代码来处理原始内容并创建一个新的,但它会导致一些延迟(1-5秒),这会使用户每次更改工作簿窗口时都感到非常烦恼。有没有一种方法可以查看窗口中是否已经存在CustomTaskPane,以避免处理和重新创建新的CustomTaskPane以避免重复任务窗格的堆叠?

Microsoft.Office.Tools.CustomTaskPane PartPhotoTaskPane;
Globals.ThisAddIn.Application.WindowActivate += Application_WindowActivate;

        void Application_WindowActivate(Excel.Workbook Wb, Excel.Window Wn)
    {
        if (PartPhotoTaskPane != null)
        {
            PartPhotoTaskPane.Dispose();
            InitalizePartPhotoViewerTaskPane(EPPF);
        }
        else
        {
            InitalizePartPhotoViewerTaskPane(EPPF);
        }
    }

    /// <summary>
    /// Start up the part photo viewer task pane
    /// </summary>
    private void InitalizePartPhotoViewerTaskPane(ExcelPartPhotoFunctions _EPPF)
    {
        //intialize the part search
        try
        {
            PartPhotoTaskPane = Globals.ThisAddIn.CustomTaskPanes.Add(new PartPhotoSearchPane(_EPPF), "Part Information", Globals.ThisAddIn.Application.ActiveWindow);
            PartPhotoTaskPane.Visible = Properties.Settings.Default.InfoPaneOpenStatus;
            PartPhotoTaskPane.Width = 260;
        }
        catch (Exception e)
        {
            MessageBox.Show("Error starting Part Info Toolbar:" + Environment.NewLine +
            e.Message + Environment.NewLine + e.StackTrace, "Error!", MessageBoxButtons.OK,
            MessageBoxIcon.Error);
        }
    }

点赞。好问题 - 我在Excel 2013的代码中做了类似的事情。我认为微软没有考虑过这种可怕的自定义新任务窗格行为,当他们将Excel更改为SDI用户界面与Excel 2013... :-( - jreichert
有相同的问题。你最终解决了这个问题吗? - anakic
1个回答

19

使用 hwnd (Globals.ThisAddIn.Application.Hwnd) 来识别 Excel 窗口。这对于使用 SDI 方法的 Office2013 和使用 MDI 窗口的旧版 Office 都适用。 以下是您可以使用的类:

public class TaskPaneManager
{
    static Dictionary<string, CustomTaskPane> _createdPanes = new Dictionary<string, CustomTaskPane>();

    /// <summary>
    /// Gets the taskpane by name (if exists for current excel window then returns existing instance, otherwise uses taskPaneCreatorFunc to create one). 
    /// </summary>
    /// <param name="taskPaneId">Some string to identify the taskpane</param>
    /// <param name="taskPaneTitle">Display title of the taskpane</param>
    /// <param name="taskPaneCreatorFunc">The function that will construct the taskpane if one does not already exist in the current Excel window.</param>
    public static CustomTaskPane GetTaskPane(string taskPaneId, string taskPaneTitle, Func<UserControl> taskPaneCreatorFunc)
    {
        string key = string.Format("{0}({1})", taskPaneId, Globals.ThisAddIn.Application.Hwnd);
        if (!_createdPanes.ContainsKey(key))
        {
            var pane = Globals.ThisAddIn.CustomTaskPanes.Add(taskPaneCreatorFunc(), taskPaneTitle);
            _createdPanes[key] = pane;
        }
        return _createdPanes[key];
    }
}

这里实际上是将Excel窗口hwnd和一些任意的字符串标识符组合在一起,以识别任务窗格。这样做的想法是支持同一个插件中的多个任务窗格。

下面是一个使用该功能从功能区操作的示例:

    private void button1_Click(object sender, RibbonControlEventArgs e)
    {
        var taskpane = TaskPaneManager.GetTaskPane("A", "Task pane type A", () => new UserControl1());
        taskpane.Visible = !taskpane.Visible;
    }

    private void button2_Click(object sender, RibbonControlEventArgs e)
    {
        var taskpane = TaskPaneManager.GetTaskPane("B", "Task pane type B", () => new UserControl2());
        taskpane.Visible = !taskpane.Visible;
    }

如果您在Excel中打开多个工作簿,每个Excel窗口都会有自己的taspaneA和taskpaneB。


你是否将此代码用于多个切换按钮/任务窗格?我正在拼命尝试让它工作,而你的代码是我找到的唯一东西。 - punkouter
@punkouter 我的VSTO插件仅有一种类型的任务窗格。如果您有多种类型的任务窗格,只需使用相同的方法但使用多个字典即可。 - anakic
每个字典都是一个单独的任务窗格?而字典中的集合是在多个Excel实例中特定任务窗格的集合?这让我感到困惑。虽然似乎是一件常见的事情(在Excel中创建多个插件),但我找不到任何代码...我不是一个好的程序员,无法自己解决问题,我很担心。 - punkouter
1
字典背后的想法是:将Excel窗口的句柄(hwnd)作为键,任务窗格实例作为值。这样,您可以确保为每个Excel窗口创建一个任务窗格实例,这对于Excel 2010(MDI样式界面)和更新版本(SDI样式界面)都能正常工作。如果您有多种类型的任务窗格,可以拥有多个字典,每个字典用于一种类型的任务窗格。具体情况取决于您的要求,例如何时需要创建任务窗格以及何时需要显示/隐藏它们。 - anakic
好的。我再试一些。这很痛苦。因此,该字典代表在 Excel 应用程序集合中的一个单独任务窗格,对吗? - punkouter
@punkouter 我已经更新了我的回答以适应你的情况。 - anakic

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