Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CustomTaskPane in Excel doesn't appear in new Workbooks

I've added a CustomTaskPane to Excel 2013 that lets users quickly search for photos. It works well and fine if the user only opens/creates one workbook. Problem is if they open another workbook or create a new one, the task pane doesn't appear in the new window that appears. It simply stays put in the original window. I know this behavior is caused by the fact I was only initializing the panel upon opening Excel. I added an event handler to the ActiveWindow event to initialize a new panel when they open another workbook.

Problem is I cannot figure out how to tell if the CustomTaskPane is already present in a window already. If it is, it simple creates another CustomTaskPane, so there are now two within that window. I wrote the following code to dispose the original and create a new one, but it introduces some lag (1-5 seconds) that would drive users crazy every time they change workbook windows. Is there a way to see if a CustomTaskPane already exists in a window to avoid disposing and recreating a new one to avoid stacking duplicate task panes?

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);
        }
    }
like image 582
Lee Harrison Avatar asked Oct 03 '13 13:10

Lee Harrison


1 Answers

Use the hwnd (Globals.ThisAddIn.Application.Hwnd) to identify the Excel window. This will work well both for Office2013 (which uses an SDI approach) and older versions of Office that use MDI windows. Here is a class you can use for this:

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

Here I'm actually combining the Excel window hwnd and some arbitrary string identifier to identify the taskpane. The idea is to support multiple taskpanes in the same addin.

Here is an example for how to use it from the ribbon:

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

If you open multiple workbooks in Excel, both Excel window will have their own taspaneA and taskpaneB.

like image 78
anakic Avatar answered Nov 13 '22 06:11

anakic