CustomTaskPane в Excel не отображается в новых книгах

Я добавил CustomTaskPane в Excel 2013, который позволяет пользователям быстро искать фотографии. Он работает хорошо и прекрасно, если пользователь открывает или создает одну книгу. Проблема в том, что если они открывают другую книгу или создают новую, панель задач не появляется в новом окне, которое появляется. Он просто остается в исходном окне. Я знаю, что это поведение вызвано тем, что я только инициализировал панель при открытии Excel. Я добавил обработчик событий в событие ActiveWindow для инициализации новой панели при открытии другой книги.

Проблема в том, что я не могу понять, как определить, уже ли CustomTaskPane уже присутствует в окне. Если это так, он просто создает другую CustomTaskPane, поэтому в этом окне есть два. Я написал следующий код, чтобы избавиться от оригинала и создать новый, но он вводит некоторое отставание (1-5 секунд), которое будет приводить пользователей в бешенство каждый раз, когда они меняют окна рабочей книги. Есть ли способ увидеть, что 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);
        }
    }

Ответ 1

Используйте hwnd (Globals.ThisAddIn.Application.Hwnd), чтобы идентифицировать окно Excel. Это будет хорошо работать как для Office2013 (который использует подход SDI), так и для старых версий Office, которые используют окна MDI. Вот класс, который вы можете использовать для этого:

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.