How to effectively maintain the state of the ribbon in outlook 2010

Summary

The Outlook 2010 programmability interface allows us to customize the ribbon. You can create an add-in for outlook using the Visual Studio 2010 and this will contain the ribbon. You need to supply the xml markup for the ribbon. Since ribbon is part of the add-in every outlook window will share the ribbon. Sometimes it is essential to manage the state of the ribbon to render the ribbon controls properly. This article will explain how to properly manage the state of the ribbon in outlook 2010 in order to render it properly.

About the sample

To begin with let us take a simple example of displaying the ribbon in Outlook 2010 with some toggle buttons. There is one more toggle button, when pressed, will disable all buttons. When you un-toggle it will enable all buttons. Here we are programmatically enabling/disabling these buttons like this.

 

State management of ribbon is useful in these scenarios .One of the common practices to address this problem is to have a Boolean variable in the ribbon class, set its value either true or false depending upon the action , call the invalidate method in the ribbon. You need to return the Boolean value appropriately in the callback function.

This at first look like it’s working. However if you open a new email again and click on the ribbon tab, you will see that the new email will also have these buttons disabled.

This is because of the fact that, when we call the invalidate method to disable the buttons, outlook will evaluate the call backs for the ribbon for all new windows.

The following section will explain how to solve this by use of the wrapper objects.

The Wrapper Objects for Inspector and Explorer windows.

  

The best way to maintain the state of the ribbon is to create the wrapper classes for the Inspector and Explorer windows. Eric Carter and Eric Lippert has written an excellent book on VSTO programming(Visual Studio Tools for Office 2007: VSTO for Excel, Word and Outlook) and he has explained how to create the wrapper objects for Inspector and Explorer windows. We will extend them to use it in the context of ribbon effectively. Basically these wrapper objects help us manage the Inspector and Explorer windows. We will store any window specific information in these classes. Since these objects are specific to each window, when we call the invalidate method of the ribbon, we can use the associated wrapper object to render the ribbon properly.

We can maintain a collection of these wrapper objects and fetch the right one based on the active window.

 

You attach an event handler to the “NewExplorer” and in the event handler you can create the instance of the explorer wrapper and add it to the wrappers collection. Given below is the code that creates the wrapper object for the Explorer window. You will also need to add the active explorer to the wrappers collection.

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

        {

           

            explorerWrappers = new Collection<ExplorerWrapper>();

            m_explorers.NewExplorer += new ExplorersEvents_NewExplorerEventHandler(OnNewExplorer);

            Explorer ActiveExplorer = Application.ActiveExplorer();

            if (ActiveExplorer != null)

            {

          ExplorerWrappers.Add(new ExplorerWrapper(ActiveExplorer));

                ActiveExplorer.SelectionChange += new ExplorerEvents_10_SelectionChangeEventHandler(OnActiveExplorerSelectionChange);

            }

        }

 

 

You also need to do the same in the “NewExplorer” even handler like this.

private void OnNewExplorer(Explorer Explorer)

        {

 

 

            //If new explorer is opened (in open new window) we add it to Wrapper

            //This is set the togggle state. GetPressed of Outlook m_ribbon will do the

            //actual toggling/untoggling

            Explorer.SelectionChange += new ExplorerEvents_10_SelectionChangeEventHandler(OnActiveExplorerSelectionChange);

  ExplorerWrapper ExplorerWrapper = new ExplorerWrapper(Explorer);

            ExplorerWrappers.Add(ExplorerWrapper);

 

        }

 

The wrapper object can now maintain the state information by using properties. The wrapper object is automatically removed from the collection by subscribing to the close event handler.

The same pattern is applied for the inspector window.

 

 

Using the Wrapper Objects in Ribbon

 

These wrapper objects are used in the ribbon object while executing the callbacks. In our example when you click on the button “EnableOrDiasbleAll”, it will dynamically enable or disable all buttons. We do this by subscribing to the “GetEnabled” callback . This will be called when we call the Invalidate/Invalidate control method of the ribbon.

We will use the wrapper object enable or disable appropriately. Given below is the code on the button that retrieves the active wrapper item that can store the Boolean value.

To attach the callback function for the button you need to add the method name in the ribbon xml and the corresponding callback function in the ribbon class like this.

 

  <toggleButton id="toggleButton3" label="EnableOrDiableAll" onAction="OnEnableOrDisableAll" showImage="false" />

public void OnEnableOrDisableAll(Office.IRibbonControl ctrl, bool isPressed)

        {

            dynamic ActiveWrapper = GetActiveOutlookWrapperItem();

            ActiveWrapper.IsButton1Enabled = isPressed;

            ActiveWrapper.IsButton2Enabled = isPressed;

            Globals.ThisAddIn.m_RibbonUI.InvalidateControl("toggleButton1");

            Globals.ThisAddIn.m_RibbonUI.InvalidateControl("normalButton1");

        }

 

You will set the “IsButton1Enabled” and “IsButton2Enabled” to true/false based on the toggle button action.

The GetActiveOutlookWrapperItem will get the wrapper object for the active window. The code is shown below

private static object GetActiveOutlookWrapperItem()

        {

                //Checks the active window

                object activeWindow;

                activeWindow = Globals.ThisAddIn.Application.ActiveWindow();

                //If it is exploer, set its background

                if (activeWindow is Microsoft.Office.Interop.Outlook.Explorer)

                {

                ExplorerWrapper ExplorerWrapper = Globals.ThisAddIn.ExplorerWrappers.FirstOrDefault(explorer => explorer.Explorer == Globals.ThisAddIn.Application.ActiveExplorer());

                    return ExplorerWrapper;

                }

                else if (activeWindow is Microsoft.Office.Interop.Outlook.Inspector)

                {

                    InspectorWrapper InspectorWrapper = Globals.ThisAddIn.InspectorWrappers.FirstOrDefault(inspector => inspector.Inspector == Globals.ThisAddIn.Application.ActiveInspector());

                    return InspectorWrapper;

 

                }

                return null;

        }

You need to subscribe the callback to the “GetEnabled” in the ribbon xml like this

<toggleButton id="toggleButton1" label="ToggleButton1" showImage="false" getEnabled="GetEnabled" onAction="OnToggleButton1Click" getPressed="GetPressed" />

                    <button id="normalButton1" label="NormalButton1" showImage="false" getEnabled="GetEnabled" onAction="OnNormalButton1Click" />

When you call the invalidate/invalidate control method of the ribbon it will execute the “GetEnabled” callback function. We will use the wrapper object in this callback to return the appropriate Boolean value. This callback will be repeatedly called for all registered buttons.

Given below is the code which does this.

public bool GetEnabled(Office.IRibbonControl ctrl)

        {

            if (ctrl == null)

                return false;

            object context = ctrl.Context;

            dynamic activeWindow = GetActiveOutlookWrapperItem();

            if (ctrl.Id == "toggleButton1")

            {

                return activeWindow.IsButton1Enabled;

            }

            else if (ctrl.Id == "normalButton1")

            {

  return activeWindow.IsButton2Enabled;

               

            }

            return true;

        }

 

Running the Sample

To run the sample

1. Download the code from here

2. Close the outlook 2010

3. Build the sample project and then press F5 to launch the Outlook 2010

4. Click on the ribbon tab “CustomTab”

5. Click on the button “EnableOrDisableAll”

This will disable all buttons. Open a new email and click on the ribbon tab “CustomTab” and verify that the button controls in this ribbon are not affected.

Additional Resources

https://msdn.microsoft.com/en-us/library/ee692172.aspx