Customizing the 2007 Office Fluent User Interface Using Visual Studio 2005 Tools for the Office System SE (Part 1 of 2)

Summary: This two-part series of articles shows you how to use Microsoft Visual Studio 2005 Tools for the 2007 Microsoft Office system to extend the user interface in solutions you build using Microsoft Office applications such as Word, Excel, and Outlook. You can learn how to customize the Office Fluent Ribbon, create and display your own custom task panes, and how to create custom forms in Outlook. (26 printed pages)

Ken Getz, MCW Technologies, LLC

Jan Fransen, MCW Technologies, LLC

December 2007

Applies to: Microsoft Visual Studio 2005 Tools Second Edition for the 2007 Microsoft Office System, Microsoft Office Excel 2007, Microsoft Office Outlook 2007, Microsoft Office Word 2007

Contents

  • Overview

  • Working with Custom Task Panes

  • Building an Application-wide Custom Task Pane

  • Introducing a Problem

  • Customizing the Office Fluent Ribbon

  • Creating the Default Add-in

  • Overriding Built-in Office Fluent Ribbon Functionality

  • Handling Custom Task Pane Visibility

  • Conclusion

  • Additional Resources

  • About the Authors

Read Part 2: Customizing the 2007 Office Fluent User Interface Using Visual Studio 2005 Tools for the Office System SE (Part 2 of 2)

Overview

The 2007 Microsoft Office system provides a wealth of user interface (UI) enhancements that make common tasks easier and that allow users to be more productive. As a developer, you want to extend these UI features so that they make tasks specific to your business easier for you and less time-consuming for your users. In the past, when you installed a new version of Microsoft Office, you got interesting and useful new features. But the UI itself looked very similar to the previous version. With the 2007 Microsoft Office system, you have no trouble keeping track of which version you are using. The new UI is not only more attractive but also easier for the average user to understand.

The most important changes for Microsoft Office developers include the new Microsoft Office Fluent UI, which is implemented in several applications in the 2007 Microsoft Office suite (including Microsoft Office Access 2007, Microsoft Office Excel 2007, Microsoft Office Outlook 2007, Microsoft Office PowerPoint 2007, and Microsoft Office Word 2007), and the new custom form regions available in Office Outlook 2007 forms. You can control these UI tools by using features available in Microsoft Visual Studio 2005 Tools Second Edition for the 2007 Microsoft Office System (Visual Studio 2005 Tools for Office SE).

A third user interface feature gets a different kind of facelift in Visual Studio 2005 Tools for Office SE and in the 2007 Office release. The result makes the custom task pane far more useful. By using Microsoft Visual Studio 2005 Tools for the Microsoft Office 2003 system, you could create custom task panes for Word and Excel. However, those task panes were always part of solutions based on documents or templates; you could not build a custom task pane solution that was available throughout the application, regardless of what document was open or current. That situation changes in Visual Studio 2005 Tools for Office SE. Now you can create task panes that are available regardless of what document is open.

This first article of a two-part series addresses some of the UI enhancements that are discussed above, and explains how to create and customize the UI by using Visual Studio 2005 Tools for Office SE.

Working with Custom Task Panes

With Visual Studio 2005 Tools for Office SE and the 2007 Microsoft Office system, Microsoft opens the custom task pane area in two important ways:

  • You can now create application-based solutions that use custom task panes by creating add-ins that target a particular application.

  • Custom task panes solutions are available in more products. You can use Visual Studio 2005 Tools for Office SE to create custom task panes for:

    • Microsoft Office Excel 2007

    • Microsoft Office InfoPath 2007

    • Microsoft Office Outlook 2007

    • Microsoft Office PowerPoint 2007

    • Microsoft Office Word 2007

NoteNote

Microsoft Office Access 2007 supports task panes, but Visual Studio 2005 Tools for Office SE does not provide templates to create Access 2007 add-ins.

You build the UI for a custom task pane just as you would for an Actions pane in a document-based solution: First, use Visual Studio 2005 Tools for Office SE to create a user control that contains the other controls that define your user interface. Then write code to add a CustomTaskPane object that includes the user control to the application. You can find the CustomTaskPane class in the Microsoft.Office.Tools namespace.

Building an Application-wide Custom Task Pane

The example that follows creates a custom task pane solution for Word 2007, but you can use the same steps to build an add-in for any application that supports custom task panes.

Suppose that you have boilerplate text that you need to insert multiple times into the same document, and each section of boilerplate text has one or more paragraphs. You saved each section of boilerplate text as a separate Word 2007 document in a folder on your hard drive. You want to create a solution that allows you to see a list of your boilerplate documents and insert one or more of them in the active document. Figure 1 shows the completed solution.

Figure 1. The sample solution allows the user to add boilerplate text from existing Word 2007 documents to the active document

Solutions adds boilerplate text to active document

Note

Although this example illustrates how to open your custom task pane when the application loads, we are not suggesting that this is a good practice. In fact, the 2007 Office System Document: UI Style Guide for Solutions and Add Ins explicitly states that a custom task pane should only open in response to a user action. After you create a working task pane, read the Creating the Default Add-in of this article to find out how to provide a custom toggle button on the Office Fluent Ribbon to open and close your custom task pane.

In the following section, you create a custom task pane solution for Word 2007.

To create a custom task pane solution for Word 2007

  1. Start Visual Studio 2005.

  2. On the File menu, click NewProject.

  3. In the New Project dialog box, browse to the Office node and then to 2007 Add-ins node under your preferred language.

  4. Select the Word Add-in template and name the add-in Boilerplate, as shown in Figure 2.

    Figure 2. Create the managed add-in by using a template

    Use a template to create a managed add-in

  5. Click OK to build the new solution.

    In Solution Explorer, note that the Visual Studio 2005 Tools for Office SE add-in template creates two projects for you—the add-in project itself, and a setup project. Although you may decide not to use the setup project, it does provide a simple way to deploy your application on client computers, and it also makes it easy to install and uninstall your add-in on your own computer. (When you run the add-in from within Visual Studio, you can test the add-in, but note that it is not deployed in the same way that it would be on a user's computer.)

    If you investigate the ThisAddIn class in the add-in project, you find that the template has inserted placeholder code for the Startup and Shutdown event handlers for the add-in. In general, you add code to these two procedures that you want to run when the add-in starts or shuts down.

  6. Add a user control for the task pane by clicking Add User Control on the Project menu.

  7. In the Add New Item dialog box, name the user control FragmentTaskPane and click Add.

  8. Use the Properties pane to change the Size property of the user control to 215, 400.

  9. Use the Toolbox to add the controls shown in Table 1 to the user control, and use the Properties pane to set property values.

    Table 1. Add controls and set properties as shown

    Control

    Property

    Value

    TextBox

    (Name)

    pathName

    MultiLine

    True

    Button

    (Name)

    browseButton

    Text

    ListBox

    (Name)

    fragmentList

    Button

    (Name)

    insertFragmentButton

    Text

    Insert Fragment

  10. Use the mouse to size and arrange the controls as shown in Figure 3.

    Figure 3. Lay out the controls as shown here

    Use mouse to layout controls, as shown

  11. Double-click the browseButton control. The code editor opens with your cursor in the event procedure for the button’s Click event.

  12. The browseButton code uses the FolderBrowserDialog class to allow the user to select a folder. FolderBrowserDialog is a member of the System.IO namespace, so add a line of code to import that namespace at the top of the class.

    Imports System.IO
    Public Class FragmentTaskPane
    
    using System.IO;
    namespace Boilerplate
    
  13. Move back to the browseButton_Click procedure and add code to open the Folder Browser dialog box and store the result in the pathname text box. (You create the FillFileList procedure in the next step).

    Private Sub browseButton_Click( _
     ByVal sender As System.Object, _
     ByVal e As System.EventArgs) Handles browseButton.Click
        Dim folderDialog As New FolderBrowserDialog
        folderDialog.Description = _
         "Select the folder containing the boilerplate fragments."
        folderDialog.ShowNewFolderButton = False
        Dim result As DialogResult = folderDialog.ShowDialog()
        If result = DialogResult.OK Then
            Me.pathName.Text = folderDialog.SelectedPath
            FillFileList(folderDialog.SelectedPath)
        End If
    End Sub
    
    private void browseButton_Click(object sender, EventArgs e)
    {
        FolderBrowserDialog folderDialog = new FolderBrowserDialog();
        folderDialog.Description = 
            "Select the folder containing the boilerplate fragments.";
        folderDialog.ShowNewFolderButton = false;
        DialogResult result = folderDialog.ShowDialog();
        if (result == DialogResult.OK )
        {
            pathName.Text = folderDialog.SelectedPath;
            FillFileList(folderDialog.SelectedPath);
        }
    }
    
  14. Add a procedure named FillFileList to add Word 2007 files in the selected folder to the list box.

    Private Sub FillFileList(ByVal pathString As String)
        Dim oFS As New DirectoryInfo(pathString & "\")
        fragmentList.Items.Clear()
        For Each oFile As FileInfo In oFS.GetFiles("*.docx")
            fragmentList.Items.Add(oFile.Name)
        Next
    End Sub
    
    private void FillFileList(string pathString)
    { 
        DirectoryInfo oFS = new DirectoryInfo(pathString + "\\");
        fragmentList.Items.Clear();
        foreach (FileInfo oFile in oFS.GetFiles("*.docx"))
        {
            fragmentList.Items.Add(oFile.Name);
        }
    }
    
  15. Open the ThisAddIn class.

  16. At the top of the file, add the following statement, so that you can work more easily with custom task panes.

    Imports Microsoft.Office.Tools
    
    using Microsoft.Office.Tools;
    
  17. Add code to the Startup method to open the custom task pane by using the FragmentTaskPane user control.

    Private Sub ThisAddIn_Startup( _
     ByVal sender As Object, _
     ByVal e As System.EventArgs) Handles Me.Startup
        Dim ctp As CustomTaskPane = _
         Me.CustomTaskPanes.Add(New FragmentTaskPane, _
         "Boilerplate Fragments")
        ctp.Width = 225
        ctp.Visible = True
    End Sub
    
    private void ThisAddIn_Startup(object sender, System.EventArgs e)
    {
        CustomTaskPane ctp = this.CustomTaskPanes.Add(
            new FragmentTaskPane(), "Boilerplate Fragments");
        ctp.Width = 225;
        ctp.Visible = true;
    }
    
  18. Add a procedure to the ThisAddIn class to insert the user-selected document at the insertion point in the active document. You call this procedure from the Click event handler of insertFragmentButton.

    Public Sub InsertFragment(ByVal fragmentPath As String)
        Try
            Application.Selection.InsertFile(fragmentPath)
        Catch ex As Exception
            MessageBox.Show("There is no active document.")
        End Try
    End Sub
    
    public void InsertFragment(string fragmentPath)
    {
        object missing = Type.Missing;
        try
        {
            Application.Selection.InsertFile(fragmentPath, ref missing,
                ref missing, ref missing, ref missing);
        }
        Catch 
        {
            MessageBox.Show("There is no active document.");
        }
    }
    
  19. Return to the FragmentTaskPane user control and double-click the insertFragmentButton control. The code editor opens to a new insertFragmentButton_Click procedure.

  20. Add code to call the InsertFragment method of the ThisAddIn class, sending the path and name of the selected user-selected document.

    Private Sub insertFragmentButton_Click( _
     ByVal sender As System.Object, _
     ByVal e As System.EventArgs) Handles insertFragmentButton.Click
        If Me.pathName.Text.Length = 0 Then
            MessageBox.Show("Please choose a path.")
            Return
        End If
        If Me.fragmentList.Text.Length = 0 Then
            MessageBox.Show("Please choose a file.")
            Return
        End If
        Globals.ThisAddIn.InsertFragment( _
         Me.pathName.Text & _
         "\" & _
         Me.fragmentList.Text)
    End Sub
    
    private void insertFragmentButton_Click( 
        object sender, EventArgs e)
    {
        if (this.pathName.Text.Length == 0)
        {
            MessageBox.Show("Please choose a path.");
            return;
        }
        if (this.fragmentList.Text.Length == 0)
        { 
            MessageBox.Show("Please choose a file.");
            return;
        }
        Globals.ThisAddIn.InsertFragment(
            this.pathName.Text + "\\" + this.fragmentList.Text);
    }
    
  21. Test your add-in by pressing CTRL+F5. Word 2007 opens, and you see the task pane as shown in Figure 4.

    Figure 4. The task pane opens at startup when the add-in is loaded

    Task pane opens at startup when add-in is loaded

  22. Click Browse to open the Browse for Folder dialog box that is shown in Figure 5.

    Figure 5. You use the common Browse for Folder dialog box to select a folder

    Use Browse for Folder dialog box to select folder

  23. Browse to a folder that contains Word 2007 (.docx) files and click OK. The fragmentList box fills with the names of the documents in the selected folder.

  24. Select one of the files in the list and click Insert Fragment. The add-in inserts the selected document’s content into the active document.

Introducing a Problem

As it is currently written, the add-in opens the task pane when the add-in itself loads, usually when Word 2007 opens. You can safely assume that the typical user does not want most task panes to remain visible from the moment Word 2007 opens. Even if the add-in is used frequently enough that it makes sense to open it at startup, the user will probably close the task pane at some point. Word 2007 provides no easy way to open the task pane again. The frustrated user would need to close and reopen Word 2007.

To investigate the issue yourself, try this with the solution that you just developed:

To identify a problem with the solution

  1. In Word 2007, close the Boilerplate Fragments task pane.

  2. Try to figure out how to open it again.

With most application-wide custom task pane solutions, you need to provide a way for the user to open the custom task pane on demand. In the 2007 Office system, your best option is to customize the application’s Office Fluent Ribbon.

Customizing the Office Fluent Ribbon

The 2007 Office system radically changes the way users interact with the host application’s menu system. Rather than grouping items by functionality into static layered menus, the 2007 Office system employs the Office Fluent Ribbon—an intelligently redesigned user interface that works with you as you interact with the application. As you modify a table in Word 2007, the Office Fluent Ribbon displays tools that help in the current context. If you select a style in the Office Fluent Ribbon, Word updates the style of the selection even before you close the gallery of styles, so you see in "real time" the effect of updating.

You can modify almost any facet of the Office Fluent Ribbon. You can add your own tabs, groups, and controls; you can hide built-in controls or override the behavior for built-in controls. In this article, you learn how you can use Visual Studio 2005 Tools for Office SE to provide a platform for customizing the Office Fluent Ribbon. For more details about the Office Fluent Ribbon in general, and additional information about the specifics of working with each control type, see the following three articles:

In general, you can customize the Office Fluent Ribbon in two ways. You can:

  1. Add Office Fluent Ribbon markup to Open XML Formats files (Office Word 2007, Office Excel 2007, Office PowerPoint 2007) directly, by inserting the XML into the document. In this case, you generally handle Office Fluent Ribbon interaction and events by using VBA code in the document itself.

  2. Create a COM add-in that provides the Office Fluent Ribbon markup and event-handling code.

Office Fluent Ribbon customizations involve two parts: You must provide the XML markup that defines the content of the customization, and you must provide code (either VBA or managed code) that both reacts to Office Fluent Ribbon control events and provides dynamic content for the Office Fluent Ribbon.

If you choose to create a COM add-in, you can create a Visual Studio 2005 shared add-in, or you can use Visual Studio 2005 Tools for Office SE to create the add-in. Using Visual Studio 2005 Tools for Office SE is much easier and more robust, and is the technique you learn in this article.

As with many technical topics, the deeper you dig into customizing the Office Fluent Ribbon, the more power you realize that you have. The Office Fluent UI offers so many rich capabilities for customization that it is not possible to cover all of them in one article. This topic focuses on only a specific set of tasks, showing how to use Visual Studio 2005 Tools for Office SE to accomplish each.

NoteNote

The following example uses Excel 2007 (rather than Word 2007), in an attempt to expand the reach of this article. The content applies directly to Word 2007 as well, and you can use this information to extend the add-in that is discussed in the previous section.

Creating the Default Add-in

When you add Office Fluent Ribbon support to your Visual Studio 2005 Tools for Office SE add-in, the Office Fluent Ribbon support template adds default behavior. Follow these steps to create an Office Fluent Ribbon customization for Excel 2007 by using Visual Studio 2005 Tools for Office SE.

To create an Office Fluent Ribbon customization for Excel

  1. In Visual Studio 2005, press CTRL+SHIFT+N to display the New Project dialog box.

  2. Click the Office project type in the language of your choice, click 2007 Add-ins, and then click the Excel Add-in template.

  3. Type a name for the add-in or leave the default name, and type a location. Click OK to create the add-in project.

  4. Click Project, and then click Add New Item.

  5. In the Add New Item dialog box, click Ribbon support. Although you can supply a name for the customization, in this simple example, accept the default name (Ribbon1). Click Add to insert the customization into your project.

Adding an Office Fluent Ribbon customization adds two files to your project: the Ribbon1.vb or Ribbon1.cs file, and the Ribbon1.xml file. (These names assume that you accepted the default item name.) The Ribbon1.xml file contains XML markup that adds a new tab with a new group to the Office Fluent Ribbon, so that you can insert an Office Fluent Ribbon customization and see its behavior without adding any extra code. Within the new group, the markup creates a toggle button control that triggers a callback procedure named OnToggleButton1 in the add-in when you change its state. In addition, the markup indicates that the customization runs a procedure named OnLoad as it loads.

<customUI 
xmlns="http://schemas.microsoft.com/office/2006/01/customui" 
onLoad="OnLoad">
  <ribbon>
    <tabs>
      <tab idMso="TabAddIns"
           label="My Tab">
        <group id="MyGroup"
               label="My Group">
          <toggleButton id="toggleButton1" 
                        size="large"
                        label="My Button"
                        screentip="My Button Screentip"
                        onAction="OnToggleButton1" 
                        imageMso="HappyFace" />
        </group>
      </tab>
    </tabs>
  </ribbon>
</customUI>

It’s worth investigating the content of the markup at this point. The root element <customUI> defines the behavior of the Office Fluent Ribbon customization as a whole, and specifies the particular schema that this customization uses. In addition, this root element specifies a callback procedure, OnLoad, which is called when the host application loads the customization. The <ribbon> element contains all the content for the customization, and the <tabs> element allows your customization to either define new tabs or to work with existing tabs. This example specifies the id attribute, indicating a new tab. It could also have specified an existing tab, using the idMso attribute (and specifying the built-in id for an existing tab). The same concept applies to the <group> element—this sample creates a group, specifying its id attribute, but could have worked with an existing group by specifying the idMso attribute and an existing group name. Every tab, group, and control within the customization must supply either an id or idMso attribute.

NoteNote

For more information about the various built-in tab, group, and control IDs, see the Office Fluent User Interface Developer Portal, and download the complete list of these values.

In addition to the id (or idMso) attribute, each element within the customization can supply other information. In this case, the <tab> and <group> elements also provide the label attribute, indicating the text they display on the Office Fluent Ribbon. Within the <group> element, this sample customization includes a <toggleButton> element, which defines the behavior of a single ToggleButton control. Most of the element’s attributes are easy to understand, but the onAction attribute is crucial—this attribute defines the name of the procedure that the host application calls, in your add-in, when you toggle the button. Office Fluent Ribbon customizations support many other types of controls.

In the Ribbon1.vb or Ribbon1.cs file, you find two classes. The main portion of the file contains code for the Ribbon1 class, which implements the IRibbonExtensibility interface. This interface requires a single procedure, GetCustomUI, which the Office application calls to retrieve the XML markup that defines the customization. In addition, this class provides the ideal location in which to add callback and layout procedures for the customization. By default, the template includes a procedure named GetResourceText, within the Helpers region of the class, which retrieves the contents of the specified resource. As you see, this procedure is generally superfluous—you can easily replace it by adding the Ribbon1.xml file to the project’s resource file. (The template cannot add the XML markup to the resource file for you without adding enormous complexity to the template itself, and so it is up to you to take this one extra step.)

The Ribbon1.vb or Ribbon1.cs file also contains a partial ThisAddIn class containing a single procedure, RequestService. The template provides this partial class totally commented out—if you want to add Office Fluent Ribbon support, you need to uncomment the code. The RequestService override provides a mechanism whereby the host application can request a service from the add-in, and retrieve information the host needs to interact with a specific service. Office Fluent Ribbon support is only one of the possible services (custom form regions in Outlook 2007 are another), and because you might already have created an override for the default RequestService method in your add-in, the Office Fluent Ribbon customization template can’t simply overwrite your existing procedure. Therefore, if you want to add an Office Fluent Ribbon customization to your add-in, you must either uncomment the procedure that the template provides, or you must modify your existing override for this procedure, adding in the Office Fluent Ribbon support. (See the section later in this article that covers Outlook custom form regions for an example of a RequestService procedure that handles both form regions and Office Fluent Ribbon customizations.)

If you examine the ThisAddIn partial class, you find the following code (reformatted to fit in this space).

Partial Public Class ThisAddIn

    Private ribbon As Ribbon1

    Protected Overrides Function RequestService( _
      ByVal serviceGuid As Guid) As Object
        If serviceGuid = GetType( _
          Office.IRibbonExtensibility).GUID Then
            If ribbon Is Nothing Then
                ribbon = New Ribbon1()
            End If
            Return ribbon
        End If

        Return MyBase.RequestService(serviceGuid)
    End Function
End Class
public partial class ThisAddIn{
  private Ribbon1 ribbon;

  protected override object RequestService(Guid serviceGuid)
  {
    if (serviceGuid == typeof(Office.IRibbonExtensibility).GUID)
    {
      if (ribbon == null)
        ribbon = new Ribbon1();
      return ribbon;
    }

    return base.RequestService(serviceGuid);
  }
}

The class declares a variable that can refer to the Ribbon1 class, and the RequestService override returns an instance of this class, on request. The host application passes to the procedure a GUID that specifies a particular service, and the procedure returns the corresponding information. In this case, the RequestService override handles only the Office.IRibbonExtensibility GUID; if it receives that particular GUID, it returns an instance of the Ribbon1 class. Given that information, the host application can display the customization, and can call procedures in your add-in in reaction to requirements (layout, or event handling) of the Office Fluent Ribbon customization.

Continue following these steps to try the default Office Fluent Ribbon customization in the template:

To use the default Office Fluent Ribbon customization in the template

  1. In Ribbon1.vb or Ribbon1.cs, uncomment the entire ThisAddIn partial class.

  2. In Solution Explorer, right-click the ExcelAddIn project, and then click Properties.

  3. Select the Resources tab to display the project’s resources.

  4. From Solution Explorer, drag Ribbon1.xml into the Resources window. This action creates a new file resource that you can reference from within your code.

  5. Close the Properties window, saving when prompted.

  6. In the Ribbon1 class, modify the GetCustomUI method so that it looks like this.

    Public Function GetCustomUI( _
      ByVal ribbonID As String) As String _
      Implements Office.IRibbonExtensibility.GetCustomUI
    
        Return My.Resources.Ribbon1
    End Function
    
    Public string GetCustomUI(string ribbonID)
    {
      return Properties.Resources.Ribbon1;
    }
    

The IRibbonExtensibility interface requires the GetCustomUI procedure, and your modification ensures that the host application receives the XML markup you’ve stored in the add-in resource file, when it needs to display your customization.

Expand the Ribbon Callbacks region of the Ribbon1 class, and you find sample callback procedures provided for you. The host application calls these procedures as required by your Office Fluent Ribbon customization. If you review the XML markup that the template created for you, you find that the customization defines an onLoad attribute, which specifies a procedure to be called as the customization loads.

<customUI 
xmlns="http://schemas.microsoft.com/office/2006/01/customui" 
onLoad="OnLoad">

In addition, the <toggleButton> element defines an onAction attribute, which specifies the procedure to be called when a user toggles the state of the control.

<toggleButton id="toggleButton1" 
              size="large"
              label="My Button"
              screentip="My Button Screentip"
              onAction="OnToggleButton1" 
              imageMso="HappyFace" />

If your customization markup includes the definition for a callback procedure, your add-in must supply the requested procedure, following strict guidelines for the procedure signature and return value. For more information about the exact details of the Office Fluent Ribbon markup, and each callback procedure, see Customizing the 2007 Office Fluent Ribbon for Developers (Part 2 of 3).

In the Ribbon1 class, you find the following two callback procedures, created for you so that you can test the default Office Fluent Ribbon customization:

Public Sub OnLoad(ByVal ribbonUI As Office.IRibbonUI)
    Me.ribbon = ribbonUI
End Sub

Public Sub OnToggleButton1( _
  ByVal control As Office.IRibbonControl, _
  ByVal isPressed As Boolean)
    If isPressed Then
        MessageBox.Show("Pressed")
    Else
        MessageBox.Show("Released")
    End If
End Sub
public void OnLoad(Office.IRibbonUI ribbonUI)
{
  this.ribbon = ribbonUI;
}


public void OnToggleButton1(
  Office.IRibbonControl control, bool isPressed)
{
  if (isPressed)
    MessageBox.Show("Pressed");
  else
    MessageBox.Show("Released");
}

The signatures for these two procedures are fixed—unless you follow the documentation carefully, the Office Fluent Ribbon cannot communicate with your add-in correctly. (For more information, see Additional Resources.)

Test running and debugging your add-in by following these final steps:

To test running and debugging your add-in

  1. Set a breakpoint on the first line inside the OnToggleButton1 procedure.

  2. Save and run your add-in by pressing F5. Visual Studio 2005 loads Excel 2007 with your add-in loaded.

  3. Click the Add-Ins tab. You can see a new group named My Group, with a button named My Button within the group.

  4. Click My Button. You should see the Visual Studio debugger. Examine the code (the point of this exercise is primarily to prove that you can debug, rather than to resolve any specific issue with debugging this code). Note that toggling the state of the button caused the application to call the OnToggleButton1 procedure of your add-in.

  5. Remove the breakpoint, and then press F5 to continue running the application.

  6. Toggle the button a few times to verify its behavior, and then close Excel, returning to Visual Studio.

This exercise proves how simple it is to create a customization by using Visual Studio 2005 Tools for Office SE. In the next set of steps, you override existing Office Fluent Ribbon functionality by using the same tools.

Overriding Built-in Office Fluent Ribbon Functionality

You can easily override built-in Office Fluent Ribbon functionality—simply supply the idMso attribute that corresponds to an existing control, and indicate the name of the procedure in your add-in that you want to call in response to user interaction. When you override existing behavior, your callback procedure is slightly different—it must include a parameter that indicates whether you want to cancel the internal behavior. For more information, see Customizing the 2007 Office Fluent Ribbon for Developers (Part 2 of 3).

Imagine that, for some reason, your users require you to prompt them to ensure that they want to save a file before saving it. (Perhaps saving a file in your particular environment is an expensive operation, and you want to ensure that users are aware of that cost before they save.) In that case, you could hook your own functionality to the Save item on the Office menu. In addition, imagine that you want to disallow the New menu item (again, for reasons that relate to your particular environment). In this exercise, you add both of these behaviors to the Excel 2007 Office Fluent Ribbon, using your Visual Studio 2005 Tools for Office SE add-in.

To override or disable an existing Office Fluent Ribbon item, you must know its idMso value. You can look up the values by using the list available in the download 2007 Office System Document: Lists of Control IDs on the Microsoft Download Center, or you can use the Customize the Quick Action Toolbar dialog box to look up the items. The latter is the approach you use here. Follow these steps to determine the idMso values you need.

To determine the idMso values

  1. Either press F5 to run your project (which loads Excel 2007 for you from Visual Studio) or run Excel 2007 manually.

  2. Click the Microsoft Office Button menu (the round button at the upper-left corner of the Excel window).

  3. At the bottom of the menu, click Excel Options.

  4. In the Excel Options dialog box, click Customize.

  5. In the Customize the Quick Access Toolbar pane, click the Choose commands from dropdown, select Office Menu, and scroll down the list of items until you find the Save item. Hover the mouse cursor over the item to see the idMso value (in parentheses), as shown in Figure 6. Using this technique, you can determine that the idMso values you need for the New and Save menus, FileSave and FileNew. Click Cancel to dismiss the dialog box.

    Figure 6. Hover over items in the Customize dialog box to determine the corresponding idMso value (listed in parentheses)

    Hover over item in Customize dialog to get idMso

  6. Exit Excel and return to Visual Studio 2005.

    Now that you have the correct idMso values, you can override the built-in functionality.

  7. In your add-in project, modify the content of the Ribbon1.xml file so that it looks like the example below. This markup indicates the two built-in items that override the standard behavior for the FileSave item and disable the FileNew item.

    <customUI 
      xmlns="http://schemas.microsoft.com/office/2006/01/customui">
      <commands>
        <command idMso="FileSave" onAction="MySave"/>
        <command idMso="FileNew" enabled="false"/>
      </commands>
    </customUI>
    

    Now that you specified the onAction attribute for the FileSave item as a procedure named MySave, you must supply that procedure in the Ribbon1 class. Add the following procedure to the Ribbon1 class, immediately following the existing OnToggleButton1 procedure. Note that this procedure, unlike the OnToggleButton1 procedure you saw previously, accepts a second parameter by reference, named cancelDefault. This parameter allows you to specify whether you want to cancel the default behavior of the item or allow the default behavior to execute after your code has completed:

    Public Sub MySave( _
      ByVal control As Office.IRibbonControl, _
      ByRef cancelDefault As Object)
        cancelDefault = _
         (MessageBox.Show("Are you sure?", "File Save", _
         MessageBoxButtons.YesNo, MessageBoxIcon.Question, _
         MessageBoxDefaultButton.Button1) = DialogResult.No)
    End Sub
    
    public void MySave(
        Office.IRibbonControl control, 
        ref bool CancelDefault)
    {
        CancelDefault = MessageBox.Show(
            "Are you sure?", "File Save", 
            MessageBoxButtons.YesNo, 
            MessageBoxIcon.Question, 
            MessageBoxDefaultButton.Button1) == DialogResult.No;
    }
    
  8. Save your project, and press F5 to run the add-in.

    After Excel loads, attempt to select the New menu item on the Office menu—it should be disabled, based on your Office Fluent Ribbon customization. Next, try saving the current workbook. Your customization displays an alert that requests confirmation of your intention to save the workbook. If you click Yes, Excel continues saving the workbook. If you click No, Excel cancels the save. Your Office Fluent Ribbon customization added both of these changes.

  9. Exit Excel and return to Visual Studio when you are ready.

Handling Custom Task Pane Visibility

In the previous section, when you learned about creating custom task panes, you also learned of a user interface challenge: How do you provide the user a way to show and hide your custom task pane? How do you handle the situation that occurs when your add-in displays the task pane, but the user closes it? To handle these issues, you can create an Office Fluent Ribbon customization that displays a ToggleButton control, allowing the user to show and hide the task pane. In addition, you can trap the VisibleChanged event of the task pane, so that you can update the state of the button to match (that is, if the user closes the task pane manually, your code causes the toggle button to update its state to indicate that the task pane has closed). To get started, follow these steps.

Add Office Fluent Ribbon customization for the task pane

  1. Using the same add-in project you have been working with, add a new user control named SampleTaskPane to the project. (See the previous section of this article for more details on creating a custom task pane.)

  2. Add a control or two to the user control, so that you can recognize the user control on a task pane.

  3. Open the ThisAddIn.vb or ThisAddIn.cs file, and add the following statements at the top of the file:

    Imports Microsoft.Office.Tools
    Imports Excel = Microsoft.Office.Interop.Excel
    
    using Microsoft.Office.Tools;
    using Excel = Microsoft.Office.Interop.Excel;
    
  4. In the ThisAddIn class, add the following variable declaration at the class level, so that you can refer to the task pane from inside or outside this class:

    Public ctp As CustomTaskPane = Nothing
    
    public CustomTaskPane ctp = null;
    
  5. Add the following code, which loads and displays the custom task pane, to the existing ThisAddIn_Startup procedure:

    ctp = _
      Me.CustomTaskPanes.Add( _
      New SampleTaskPane, "Sample Task Pane")
    ctp.Width = 200
    ctp.Visible = True
    
    ctp = this.CustomTaskPanes.Add(
       new SampleTaskPane(), "Sample Task Pane");
    ctp.Width = 200;
    ctp.Visible = true;
    }
    
  6. Replace the contents of the customization in Ribbon1.xml with the following markup, which creates the ToggleButton control for the demonstration, in a new group on the main tab.

    <customUI 
      xmlns="http://schemas.microsoft.com/office/2006/01/customui" 
      onLoad="OnLoad">
      <ribbon>
        <tabs>
          <tab idMso="TabHome">
            <group id="CustomTaskPanesGroup"
                   label="Handle Task Pane">
              <toggleButton id="sampleTaskPaneToggleButton" 
                     size="large"
                     label="Sample Task Pane"
                     screentip=
                        "Show or hide the sample task pane"
                     imageMso="Diamond" 
                     onAction="HandleTaskPane"
              />
            </group>
          </tab>
        </tabs>
      </ribbon>
    </customUI>
    
  7. Save and run your application, verifying that you see the custom task pane and the Office Fluent Ribbon customization. Exit Excel when you are done.

  8. Your Office Fluent Ribbon customization requires you to supply code to show and hide the custom task pane. Add the following procedure to the Ribbon1 class (in the Ribbon Callbacks region, if you like), which shows and hides the custom task pane:

    Public Sub HandleTaskPane( _
      ByVal control As Office.IRibbonControl, _
      ByVal isPressed As Boolean)
    
        Globals.ThisAddIn.ctp.Visible = isPressed
    End Sub
    
    public void HandleTaskPane(
      Office.IRibbonControl control, Boolean isPressed)
    {
        Globals.ThisAddIn.ctp.Visible = isPressed;
    }
    
  9. Save and run the project again, and verify that you can hide and show the custom task pane by using the toggle button on the Office Fluent Ribbon. Note that the initial state of the toggle button is incorrect, and that if you manually close the task pane, the button does not update to match the current state. Exit Excel and return to Visual Studio after you finish.

    To support dynamic functionality, the Office Fluent Ribbon customization model allows the Office Fluent Ribbon markup to specify callback procedures that handle control state, as well as handling control events (as you saw in the previous example). For a ToggleButton control, you can specify (among other attributes) the getPressed attribute. The value of this attribute supplies the name of a procedure that the Office Fluent Ribbon calls to determine the pressed state of the button. In this procedure, you supply code that calculates whether the button should appear depressed, returning True to indicate that it is pressed or False to indicate that it is not.

  10. In the Ribbon1 class, add a public procedure that allows code in the add-in’s class to force the Office Fluent Ribbon to refresh. This code calls the InvalidateControl method of Office Fluent Ribbon, which forces the specified control to refresh its display:

    Public Sub Refresh()
        ribbon.InvalidateControl("sampleTaskPaneToggleButton")
    End Sub
    
    public void Refresh()
    {
        ribbon.InvalidateControl("sampleTaskPaneToggleButton");
    }
    
  11. In the Ribbon1 class, add the status callback that determines the state of the toggle button, based on the visibility of the custom task pane:

    Public Function GetPressed( _
      ByVal control As Office.IRibbonControl) As Boolean
        Return Globals.ThisAddIn.ctp.Visible
    End Function
    
    public Boolean GetPressed(Office.IRibbonControl control)
    {
        return Globals.ThisAddIn.ctp.Visible;
    }
    

    In Ribbon1.xml, add support for retrieving the pressed state of the button by calling the GetPressed method you just created. Modify the XML markup so that it looks like this, adding the getPressed attribute.

    <customUI 
      xmlns="http://schemas.microsoft.com/office/2006/01/customui" 
      onLoad="OnLoad">
      <ribbon>
        <tabs>
          <tab idMso="TabHome">
            <group id="CustomTaskPanesGroup"
                   label="Handle Task Pane">
              <toggleButton id="sampleTaskPaneToggleButton" 
                     size="large"
                     label="Sample Task Pane"
                     screentip=
                        "Show or hide the sample task pane"
                     imageMso="Diamond" 
                     onAction="HandleTaskPane"
                     getPressed="GetPressed"
              />
            </group>
          </tab>
        </tabs>
      </ribbon>
    </customUI>
    

    In the ThisAddIn class in the Ribbon1.vb file, add support for handling the VisibleChanged event of the task pane. Add this event handler to the class, which calls the Refresh method of the Ribbon1 class, updating the pressed state of the toggle button when the visibility changes:

    Private Sub HandleVisibleChanged( _
      ByVal sender As Object, ByVal e As EventArgs)
        ribbon.Refresh()
    End Sub
    
    private void HandleVisibleChanged(Object sender, EventArgs e)
    {
        ribbon.Refresh();
    }
    
  12. Finally, modify the existing Startup and Shutdown procedures in the ThisAddIn.vb file, hooking and unhooking the VisibleChanged event of the task pane:

    Private Sub ThisAddIn_Startup( _
      ByVal sender As Object, _
      ByVal e As System.EventArgs) _
      Handles Me.Startup
    
        ctp = _
          Me.CustomTaskPanes.Add( _
          New SampleTaskPane, "Sample Task Pane")
        ctp.Width = 200
        ctp.Visible = True
        AddHandler ctp.VisibleChanged, AddressOf HandleVisibleChanged
        ribbon.Refresh
    End Sub
    
    Private Sub ThisAddIn_Shutdown( _
      ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles Me.Shutdown
    
        RemoveHandler ctp.VisibleChanged, _
          AddressOf HandleVisibleChanged
    End Sub
    
    private void ThisAddIn_Startup(
      object sender, System.EventArgs e)
    {
        ctp = this.CustomTaskPanes.Add(
          new SampleTaskPane(), "Sample Task Pane");
        ctp.Width = 200;
        ctp.Visible = true;
        ctp.VisibleChanged += new EventHandler(HandleVisibleChanged);
        ribbon.Refresh();
    }
    
    private void ThisAddIn_Shutdown(object sender, System.EventArgs e)
    {
        ctp.VisibleChanged -= new EventHandler(HandleVisibleChanged);
    }
    
  13. Save and run your project. Now, as Excel starts up, the toggle button appears in the correct state. You can use the toggle button to show and hide the task pane. If you close the task pane manually, the button updates appropriately.

  14. Exit Excel when you finish.

Conclusion

As you see, customizing the Office Fluent Ribbon takes a little bit of effort—Visual Studio does not provide a user interface that can be used to perform the customization—but the concepts are not difficult. This article presents some examples, taking advantage of the features provided by Visual Studio 2005 Tools for Office SE. The second article in this series explores additional customization in other 2007 Microsoft Office applications such as Office Outlook 2007 and Office Word 2007.

Additional Resources

For more information, see the following resources:

About the Authors

Ken Getz is a developer, writer, and trainer, working as a senior consultant with MCW Technologies, LLC, a Microsoft Solution Provider. Ken co-authored AppDev's C#, ASP.NET, Visual Basic, and ADO.NET courseware. He has co-authored several technical books for developers, including the best-selling ASP.NET Developer's Jumpstart, the Access Developer's Handbook series, and the VBA Developer's Handbook series. Ken is a technical editor for Advisor Publications' VB.NET Technical Journal, and he is a columnist for both MSDN Magazine and CoDe Magazine. Ken speaks regularly at a large number of industry events, including Advisor Media's Advisor Live events, FTP's VSLive, and Microsoft Tech-Ed.

Jan Fransen is a writer, trainer, and developer specializing in Microsoft products. Jan authored AppDev’s Microsoft Visual Studio Tools for Office, Microsoft Office, and Visual Basic for Applications courseware, and co-authored AppDev’s .NET Framework 2.0 courseware. Jan has contributed to books about Microsoft Office, written white papers for publication on MSDN, and created samples designed to help developers get up to speed quickly on new Microsoft products and features.