Synchronizing Ribbon and Task Pane

The new custom task pane model in Office 2007 is interesting. It certainly opens up a wide range of opportunities for providing a better user experience than the doc-level ISmartDocument-based task pane. It’s also interesting in that it provides some challenges for Word and InfoPath developers – see previous post.

The thing that’s most immediately obvious is that individual add-in developers now have a lot of freedom in how they design the resulting user experience. Office provides the basic framework for hooking up your task pane, and it leaves you to implement the task pane in whatever way you see fit. Consider that, unlike the task pane in Office 2003, the new task pane does not stack. Rather, it tiles. So, if the application is running say 10 add-ins, and each add-in implements one or more task panes, if they’re all visible at the same time, the user will run out of screen real estate pretty fast.

To mitigate this, the Office UI guidelines suggest that you should never develop an add-in which programmatically forces the task pane on the user outside their control. Your custom task pane should not be visible on startup, and the user should always be able to make it visible or hidden at will. The simplest approach is to provide a ribbon button to allow the user to toggle the task pane visibility.

By implication, you should never assume in your add-in code that your task pane is visible at any given time. That means you need to sink the VisibleChangedEvent on your task pane so you always know its state – the user might open/close your task pane via the custom ribbon button you conveniently supply, but they might also simply hit the X box to close it directly. By further implication, you’re responsible for synchronizing the toggled state of your ribbon button (assuming you’re providing a togglebutton) to the actual state of the task pane.

Here’s how you could set this up in a very simple way. The following code snippets assume you’ve created a VSTO add-in and added a simple ribbon class  (via the Add Item project wizard). Here’s the markup for my togglebutton:

<toggleButton id="standardToggle"





The interesting stuff in my ribbon class is after the #region block for “standard stuff”:


public class RibbonX : Office.IRibbonExtensibility



    #region Standard stuff


    private Office.IRibbonUI ribbon;


    public RibbonX()




    public void OnLoad(Office.IRibbonUI ribbonUI)


        this.ribbon = ribbonUI;



    public string GetCustomUI(string ribbonID)


        return Properties.Resources.RibbonX;





    private bool isTaskPaneVisible;


    public bool IsTaskPaneVisible


        get { return isTaskPaneVisible; }



            isTaskPaneVisible = value;





    public bool GetPressed(Office.IRibbonControl control)


        switch (control.Id)


            case "standardToggle":

                return isTaskPaneVisible;


                return false;




    public void OnStandardToggle(Office.IRibbonControl control, bool isPressed)


        Globals.ThisAddIn.ctp.Visible = isPressed;




So, I have a bool field in my ribbon class, exposed via a property which invalidates my ribbon togglebutton inside the setter. Invalidating my control will make Office call back to my GetPressed method. In my GetPressed method, I return the current value of the flag I’m using to cache the visible state of my task pane.  When the user clicks my togglebutton, I set the visible state of the task pane.

Over in my add-in’s main class,  I make sure my CustomTaskPane field is accessible to my ribbon class. I create the task pane in my Startup method, and at the same time I hook up an event handler for the VisibleChanged event. When I get this event, I toggle the state of the bool flag in my ribbon class:


private RibbonX ribbon;

internal CustomTaskPane ctp;


private void ThisAddIn_Startup(object sender, System.EventArgs e)


    this.Application = (Excel.Application)ExcelLocale1033Proxy.Wrap(typeof(Excel.Application), this.Application);


    ctp = this.CustomTaskPanes.Add(new ContosoAqua.ContosoControl(), "Contoso");

    ctp.Visible = false;

    ctp.VisibleChanged += new EventHandler(ctp_VisibleChanged);



void ctp_VisibleChanged(object sender, EventArgs e)


    ribbon.IsTaskPaneVisible = !ribbon.IsTaskPaneVisible;



Pretty simple, yes?

Another thing you should do is to design your add-in so that it does not need multiple task panes. One way to achieve this is to use a TabControl on your task pane – this  is a very simple and cheap mechanism to provide your users with multiple different controls for each different context that you’ve identified for your solution, yet at the same time reduce the impact on their screen real estate.

Implementing such a task pane is pretty trivial. Here’s  one I built earlier – I have a UserControl with a TabControl with 3 tabs. I’ve populated each tab with the controls I want for that context (actually, I created a separate UserControl with the controls I wanted for each tab). Then create a CustomTaskPane using the outer UserControl, and Robert is your father’s brother:

Comments (7)

  1. sharad says:

    I am using VSTO 2008 (v3)

    Now i am not able to use getPressed="GetPressed"

    as ribbon designer is not giving any such flexibility.

    as a result i can control task pane from checkbox but i can not control checkbox from taskPane (say action is closing task pane using X, still checkbox remains checked)and GetPressed function is not being invoked.

    any help is much appreciated.

  2. Jordan P says:

    Your RibbonX ribbon is never instantiated, so how can you use it within ctp_VisibleChanged? Am I missing something?

  3. Garry Trinder says:

    Jordan – I haven’t listed the complete code for the add-in, because creating a simple Ribbon was not the main focus of this post. I mentioned that I added the Ribbon code using the Add Item project wizard. This will add code to override RequestService (VSTO 2005 SE) or CreateRibbonExtensibilityObject (VS 2008), and this generated code includes the instantiation of the object.

  4. Jordan P says:


      Thank you for responding. My apologies in misconstruing the intent of your posting, for it is pretty complete code listing (for the ribbon and addin classes) sans the little portion for the ribbon variable instantiation. I had been following the examples of MS. They had mentioned that the 2005 VSTO generated a commented class within the ribbon class, where you were to instantiate the ribbon. Mine did not generate, so I had been looking for examples of a ribbon/taskpane that worked. What you did offer in your post was enough for me to finish successfully and I thank you for that.


  5. Aziz says:

    Hi Andrew,

    Is there a way to access the ribbon control outside the ribbon.cs(class file generated by the ribbon support item). I want to disable the buttons on my ribbon dynamically through the thisaddin.cs.

    Is this achievable? if yes , how?

    (I’ve added the ribbon by selecting the ribbon support option in the add new item and not through the ribbon designer).

    Any help is appreciated.


  6. Garry Trinder says:

    Aziz – yes, you can setup GetEnabled methods for your controls, which you code to enable or disable your controls. Then, you need to force the Ribbon to be re-rendered. You do this by calling IRibbonUI.Invalidate or IRibbonUI.InvalidateControl methods. You get to these methods because the Ribbon item wizard generates a class that includes an IRibbonUI object as a field. From your add-in class, you can get to this IRibbonUI field if you declare it as internal or public (or declare an internal or public property that accesses the private field). See here for details: Also here:

Skip to main content