Customizing the Ribbon in Outlook 2007
This content is outdated and is no longer being maintained. It is provided as a courtesy for individuals who are still using these technologies. This page may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist.
**Summary: **Learn how to customize the Ribbon in Outlook 2007 to reflect the state of a given Outlook item displayed in an Inspector window. (25 printed pages)
Randy Byrne, Senior Program Manager
Microsoft Corporation
Published: June 2006
Updated: February 2007
**Applies to: **Microsoft Office Outlook 2007, Visual Studio 2005 Tools for Office Second Edition
**Download: **Outlook 2007 Ribbon Extensibility Add-In
Contents
Introduction to Ribbon Customization
Outlook Ribbon Extensibility Sample Add-In
Installation Instructions
What Happens with Existing Code
Modifying Your Code to Use Ribbon Extensibility
VSTO 2005 SE and the Ribbon
Conclusion
Additional Resources
Introduction to Ribbon Customization
The Microsoft Office Fluent user interface (UI) is the terminology used to describe the new UI for the 2007 Microsoft Office system. The Ribbon is a component of the Microsoft Office Fluent UI. Unlike other applications in the 2007 Microsoft Office system, such as Microsoft Office Word, Microsoft Office Excel, and Microsoft Office PowerPoint, which rely exclusively on the Ribbon, Microsoft Office Outlook 2007 uses both the Ribbon and command bars. Additionally, Outlook does not support document-level customizations of the Ribbon. You can customize the Ribbon only by implementing the IRibbonExtensibility interface in an Outlook add-in. In the main application window, Outlook displays the command bars that are familiar to users of earlier versions of Microsoft Office. In item windows, such as a mail message window where authoring is the central user experience, Outlook uses the new Ribbon. To provide the best authoring experience for end-users, Outlook item windows display item-specific Ribbons. From an object model perspective, an Outlook item window is an Inspector object. If you have existing code that uses the object returned by the Inspector.CommandBars property to customize command bars for standard or custom item types, this article describes how Ribbon extensibility improves your existing customizations of command bars for an Outlook Inspector.
The main application window, known as an Explorer object, still uses command bars introduced in earlier versions of Office. For an Outlook Explorer, you continue to use the object returned by the Explorer.CommandBars property to customize the Outlook window. As a prerequisite for this article, you must know how to write code for the Office CommandBars object model so that I will not spend much time discussing the CommandBars object model.
There are several excellent blogs and technical articles that discuss Ribbon extensibility in detail on MSDN. For a comprehensive view of all aspects of the Ribbon, a must-read is Jensen Harris: An Office User Interface Blog. For developer information about Ribbon extensibility for tabs, groups, and controls, see Customizing the 2007 Office Fluent Ribbon for Developers (Part 1 of 3), Customizing the 2007 Office Fluent Ribbon for Developers (Part 2 of 3), and Customizing the 2007 Office Fluent Ribbon for Developers (Part 3 of 3) by Frank Rice. I urge you to view these references because I do not repeat the comprehensive listing of Ribbon XML Schema and callback signatures that you can find on MSDN. In this article, I focus on what you have to know about the Outlook implementation of the Ribbon.
Outlook Ribbon Extensibility Sample Add-In
The Outlook Ribbon extensibility sample add-in is a learning tool that can help you understand how to customize an item-level Outlook Ribbon using an add-in. The Outlook Ribbon extensibility sample add-in addresses the following important new areas:
Providing Ribbon XML for an item based on the RibbonID parameter that was passed in the IRibbonExtensibility.GetCustomUI method
Understanding how to use the IRibbonControl.Context object that is passed in Ribbon callbacks. IRibbonControl.Context represents the Inspector object that is about to be displayed in Outlook
Using the OutlookInspector class to track the state of multiple Inspector windows and to track property change events on a given item displayed in its Inspector window
After a state change in an item, calling the IRibbonUI.InvalidateControl method to invalidate the Ribbon and cause callbacks to occur again
The sample code included in this article uses both Microsoft Visual C# and Microsoft Visual Basic. The code examples require Microsoft Visual Studio 2005 and Microsoft Office Outlook 2007. The sample code is available in the Outlook Ribbon extensibility sample solutions named OutlookRibbonXVB and OutlookRibbonXCS, where the VB suffix indicates the Visual Basic .NET version and the CS suffix indicates the Visual C# version. Microsoft Visual Studio 2005 Tools for the 2007 Microsoft Office System (VSTO 2005 SE) samples are also provided. The Visual Studio Tools for Office samples use a VSTO suffix to indicate a VSTO 2005 sample. For example, the VSTO sample solutions for this article are named OutlookRibbonXVB_VSTO and OutlookRibbonXCS_VSTO. The VSTO samples use basically the same code that appears in this article, except that VSTO add-ins implement IRibbonExtensibility in a separate class from the ThisAddin class (comparable to the Connect class). In the respective VSTO samples, the COM-visible classes that implement the Ribbon are named OutlookRibbonXVB and OutlookRibbonXCS. The inline code examples provided in this article can help you understand how to customize the Ribbon in Outlook 2007.
Note |
---|
The VSTO 2005 code samples do not include a custom action to set code access security programmatically to full trust for the folder where the sample is installed. For the installed VSTO 2005 add-ins to operate correctly, you must set code access security to full trust manually by using the CASPOL tool or the .NET Framework 2.0 Configuration application in the Windows control panel. The VSTO 2005 samples will operate correctly without setting full trust permission if you run the sample in debug mode. More information about code access security and VSTO 2005 is available on MSDN. |
Installation Instructions
Before you can run the Outlook Ribbon extensibility sample add-ins, you must download the sample code installation package.
To install the Outlook Ribbon extensibility sample add-in
Download the sample code installation package, and double-click the downloaded file to start the setup process. Follow the steps in the setup wizard to complete the installation.
The sample code installation package will install OutlookRibbonXCS, OutlookRibbonXVB, OutlookRibbonXCS_VSTO, and OutlookRibbonXVB_VSTO in the My Documents\Visual Studio 2005\Projects folder.
Note The precise name of your personal documents folder depends on the operating system installed on your computer. Windows Vista names your personal documents folder Documents. Windows XP names your personal documents folder My Documents. Adjust the path specifications for your personal documents folder according to your installed operating system.
If you are using Visual C# Express Edition or Visual Basic Express Edition to open the sample add-ins, you will be unable to build the setup/deployment project. Therefore, you will be unable to install the sample add-ins.
To run the Outlook Ribbon extensibility sample
Close Outlook 2007.
In the MyDocuments\Visual Studio 2005\Projects\SolutionName folder, open the SolutionName solution.
In Solution Explorer, click AddinName Setup.
On the Build menu, click Build AddinName Setup.
On the Project menu, click Install to install the solution.
Start Outlook to start the add-in in Run mode, or press F5 to start the add-in in Debug mode.
If Outlook does not start in Debug mode, complete the following procedure.
To start Outlook in Debug mode
In Solution Explorer, select AddinName.
On the Project menu, click AddinName Properties, and then click the Debug tab.
Under Start Action, select the Start External Program option, and then click Browse (...).
In the Drive:\Program Files\Microsoft Office\Office12 folder, click Outlook.exe.
Press F5 to start the add-in in Debug mode.
What Happens with Existing Code
If you have already written code to customize Inspector command bars in an Outlook add-in or an Outlook 97 to Outlook 2003 custom form, you must know what that code does in Outlook 2007. Your existing code will still work. However, your Inspector command bars code will put your command bar customizations on the Add-ins tab on the Ribbon. This might be acceptable to you, or you might decide that the Add-ins tab experience is less than optimal for your command UI. In this case, you should consider updating your code to use Ribbon extensibility.
The following table shows command bar customization bahavior in Outlook 2007.
Table 1. Command Bar customizations in Outlook 2007
Entry Point |
Outlook 2007 Behavior |
---|---|
Explorer.CommandBars |
Existing code continues to work because Outlook 2007 uses command bars in the Explorer window. |
Inspector.CommandBars to add custom CommandBarControls on a built-in menu |
Existing code continues to work, but customizations appear on the Menu Commands group on the Add-ins tab. Menu customizations for all add-ins that customize built-in menus appear together in the Menu Commands group. |
Inspector.CommandBars to add custom CommandBarControls on a built-in toolbar |
Existing code continues to work, but customizations appear on the ToolbarCommands group on the Add-ins tab. Toolbar customizations for all add-ins that customize built-in toolbars appear together in the Toolbar Commands group. |
Inspector.CommandBars to add a custom toolbar |
Existing code continues to work, but customizations appear on the Custom Toolbar group on the Add-ins tab. Custom toolbars for all add-ins appear together in the Custom Toolbar group. |
Word.CommandBars to add custom toolbars and controls for WordMail in Outlook 2000 to Outlook 2003 |
Existing code does not work. Word macros stored in normal.dot or email.dot no longer run, because WordMail in Outlook 2007 runs under Outlook instead of Word. Prior to the release of Outlook 2007, Word macros that added custom toolbars and controls executed from Word. Existing code must be updated for Outlook 2007. If you have an extensive library of WordMail macros, consider providing that code in an Outlook add-in. Use the Inspector.WordEditor object to return a Word Document object displayed in the current Inspector. Because WordMail is integrated into Outlook, all item types including appointments, contacts, and tasks support the rich editing environment in Word. |
Inspector Command Bars
This section shows an example of Inspector command bar customization in the Outlook Ribbon extensibility sample add-in. The Ribbon extensibility sample add-in adds a Color Widgetcustom command bar to an Outlook contact item, but only if the contact has a mailing address. Figure 1 shows the Color custom toolbar on the Add-ins tab of the Outlook contact inspector. Notice that the name of the Color Widget custom command bar does not appear in the Custom Toolbars group.
Figure 1. Color custom toolbar in Custom Toolbars group on Add-ins tab
Due to space limitations, I will not explain the sample code that creates the custom Color Widget toolbar. In the Outlook Ribbon extensibility sample add-in, examine the CreateColorWidgets and RemoveColorWidgets procedures in the OutlookInspector class. The custom Color Widgets toolbar is built using the events listed in the following table.
Table 2. Custom color Widgets toolbar events
Event |
Description |
---|---|
Inspectors_NewInspector in Connect |
If the Inspector is not found in m_Windows, creates a new instance of OutlookInspector and adds the instance to m_Windows. |
ContactItem_Open in OutlookInspector |
Adds the custom toolbar using the CreateColorWidgets procedure. If the ContactItem has a BusinessAddress, HomeAddress, or OtherAddress, makes the custom toolbar visible. |
ContactItem_Close in OutlookInspector |
Removes the custom toolbar using the RemoveColorWidgets procedure. |
Voting Options
Outlook 2007 continues to support voting options on messages. Voting options are used to present a list of choices to message recipients and to track their responses. If you create voting options programmatically by setting a semicolon-delimited list of values for the VotingOptions property of a MailItem, those voting options appear in the Vote menu in the Respond group of the Ribbon of an Outlook "read" note. A read note is the e-mail message that is received by the recipient. For example, the following code creates voting options on a "compose" note.
private void OrderPizza_Click(object sender, EventArgs e)
{
Outlook.Application outlookApplication = new Outlook.Application();
Outlook.MailItem mail = (
Outlook.MailItem)outlookApplication.CreateItem(
Outlook.OlItemType.olMailItem);
mail.VotingOptions = "Cheese; Mushroom; Sausage; Combo; Veg Combo";
mail.Subject="Pizza Order";
mail.Display(false);
}
When the user sends the Pizza Order message to team members, the voting options are displayed to recipients, as shown in Figure 2. When the sender of the original pizza order receives the response, recipient choices are tallied on the Tracking page of the message in the sender's Sent Items folder.
Figure 2. Voting Options menu appears on the Respond group of a received message
Custom Actions
Custom actions can also be created programmatically and will appear on the Ribbon in the Actions group on the Message tab. Custom actions can be added at design time using the Outlook Forms Designer, specified in form region markup, or created programmatically by calling the Add method on the Actions collection object. The following code adds a custom action named Reply with Voice Mail to the active inspector shown in Figure 3.
private void ReplyWithVoiceMail_Click(object sender, EventArgs e)
{
Outlook.Application outlookApplication = new Outlook.Application();
Outlook.MailItem mail = (
Outlook.MailItem)outlookApplication.ActiveInspector().CurrentItem;
Outlook.Action action = mail.Actions.Add();
action.Name = "Reply with Voice Mail";
action.ReplyStyle = Outlook.OlActionReplyStyle.olUserPreference;
action.ResponseStyle = Outlook.OlActionResponseStyle.olOpen;
action.CopyLike = Outlook.OlActionCopyLike.olReply;
action.MessageClass = "IPM.Post.Voice Message";
mail.Save()
}
Figure 3. Custom Actions menu appears in the Actions group
Modifying Your Code to Use Ribbon Extensibility
Ribbon customization in Outlook 2007 uses the add-in model. Outlook does not offer document-level customization of the Ribbon similar to Word, Excel, or PowerPoint. The first question that you should ask yourself is whether your existing code requires modification to use Ribbon extensibility. If your existing code adds custom commands to Inspector command bars, consider reworking your code for Ribbon extensibility. If you do not modify your code and you modify Inspector command bars, your customizations will appear in the global groupings of the Add-ins tab in an Inspector window.
Because these groups do not state the source of the command, user confusion will occur. Aside from the user impact, the Ribbon offers a much wider range of controls compared to the Office command bars object model. You can implement button, toggle button, check box, combo box, drop-down, or gallery controls by writing Ribbon markup. I urge you to take a close look at updating your existing code to use the control palette of the Ribbon. If you are designing a solution that runs only on Outlook 2007, then your decision is a simple one. Implement the Ribbon and take advantage of the rich programming model for Ribbon extensibility.
Now let's discuss how the sample Outlook Ribbon extensibility add-in provides Ribbon customization for an Outlook contact item. Figure 4 shows the Color Widgets toolbar transformed into a Ribbon group. Unlike the behavior of command bar customizations on the Add-ins tab, a pop-up window identifies the add-in that has added the control to the Ribbon when you move the pointer over the control. In this case, the Color Widgets group participates as a first-class citizen of the Ribbon. Next, we examine the markup required for implementing Color Widgets.
Figure 4. Color Widgets group on the Contact Inspector Ribbon
Authoring Ribbon XML
The first step in customizing the Ribbon is writing declarative XML markup that specifies the tabs, groups, and controls for your customization. In the case of the Outlook Ribbon extensibility sample add-in, the Ribbon XML is contained in a resource in the add-in project. Because Color Widgets is a very simple example, the markup is simple also. Here is the customUI.xml resource from the sample.
<customUI xmlns="http://schemas.microsoft.com/office/2006/01/customui"
onLoad="Ribbon_OnLoad">
<ribbon>
<tabs>
<tab idMso="TabContact">
<group id="ColorWidgetsGroup"
getVisible="ColorWidgetsGroup_GetVisible"
getLabel="ColorWidgetsGroup_GetLabel">
<button
id="ColorButton"
getLabel = "ColorButton_GetLabel"
getSupertip="ColorButton_GetSupertip"
onAction ="ColorButton_Action"
imageMso="MoreColors"
/>
<comboBox
id="ColorCombo"
onChange ="ColorCombo_OnChange"
getText="ColorCombo_GetText"
getItemCount ="ColorCombo_GetItemCount"
getItemLabel ="ColorCombo_GetItemLabel"
/>
</group>
</tab>
</tabs>
</ribbon>
</customUI>
This Ribbon markup specifies two controls, a button and combo box, for the Color Widgets group. The Color Widgets group appears on the Contact tab, which is specified by the idMso attribute of TabContact. The markup specifies several callbacks that run when a contact item is opened. These callbacks are used to execute an action, supply text for controls, specify an image, or control visibility of the Color Widgets group. To keep things simple in the sample code, this markup uses built-in images specified by imageMso instead of dynamically loading an image by using the GetImage callback for the Color button.
The Ribbon extensibility articles cited earlier cover the schema for Ribbon XML so that I will not describe authoring the Ribbon XML in detail. For more information about control IDs for built-in controls for Outlook Ribbons, see 2007 Office System Document: Lists of Control IDs. The important aspect of authoring Ribbon XML for Outlook is that different item types can require a separate XML markup. To customize an Appointment and a Contact item, for example, you should consider adding two markup documents to your add-in resources. This point is explained more when I discuss how Ribbon markup is loaded in the IRibbonExtensibility.GetCustomUI procedure.
IRibbonExtensibility Interface
An Outlook add-in that customizes the Ribbon must implement the Office.IRibbonExtensibility interface.
In the Outlook Ribbon sample add-in, this interface is implemented in the Connect class. In the Outlook Ribbon extensibility VSTO sample add-in, this interface is implemented in the OutlookRibbonXVB or OutlookRibbonXCS classes. After you have implemented IRibbonExtensibility, you write code to return your Ribbon markup in the IRibbonExtensibility.GetCustomUI procedure. Before I show you sample code for GetCustomUI, you must understand exactly how GetCustomUI is called in Outlook 2007. The behavior of GetCustomUI is unique to Outlook:
GetCustomUI is not called until an Outlook Inspector is opened by a user or a programmatic action.
Selecting an item in the Reading Pane does not call GetCustomUI. The item must be opened in an Outlook Inspector.
GetCustomUI is called one time only, when the Ribbon is first loaded for a given RibbonID.
RibbonID is a unique string that identifies the type of Inspector. RibbonID correlates to the item's message class. However, different RibbonIDs can be associated with the same message class.
In some cases, such as a MailItem or PostItem, GetCustomUI is called one time when the first compose note is displayed (where RibbonID is "Microsoft.Outlook.Mail.Compose") and one time when the first read note is displayed (where RibbonID is "Microsoft.Outlook.Mail.Read").
The unique Ribbon IDs used by Outlook are listed in Table 3.
Table 3. Unique Ribbon IDs used by Outlook
Ribbon ID |
Message Class |
---|---|
Microsoft.Outlook.Mail.Read |
IPM.Note.* |
Microsoft.Outlook.Mail.Compose |
IPM.Note.* |
Microsoft.Outlook.MeetingRequest.Read |
IPM.Schedule.Meeting.Request or IPM.Schedule.Meeting.Canceled |
Microsoft.Outlook.MeetingRequest.Send |
IPM.Schedule.Meeting.Request |
Microsoft.Outlook.Appointment |
IPM.Appointment.* |
Microsoft.Outlook.Contact |
IPM.Contact.* |
Microsoft.Outlook.Journal |
IPM.Activity.* |
Microsoft.Outlook.Task |
IPM.Task.* and IPM.TaskRequest.* |
Microsoft.Outlook.DistributionList |
IPM.DistList.* |
Microsoft.Outlook.Report |
IPM.Report.* |
Microsoft.Outlook.Resend |
IPM.Resend.* |
Microsoft.Outlook.Response.Read |
IPM.Schedule.Meeting.Resp.* |
Microsoft.Outlook.Response.Compose |
IPM.Schedule.Meeting.Resp.* |
Microsoft.Outlook.Response.CounterPropose |
IPM.Schedule.Meeting.Resp.* |
Microsoft.Outlook.RSS |
IPM.Post.Rss.* |
Microsoft.Outlook.Post.Read |
IPM.Post.* |
Microsoft.Outlook.Post.Compose |
IPM.Post.* |
Microsoft.Outlook.Sharing.Read |
IPM.Sharing.* |
Microsoft.Outlook.Sharing.Compose |
IPM.Sharing.* |
Note |
---|
Sticky notes do not implement the Ribbon, so IPM.StickyNote is not listed in the table of Ribbon IDs and message classes. |
In most cases in the table, the message class is represented as IPM.Type.*. This notation means that either the first instance of the base message class (for example, IPM.Contact) or a custom message class (IPM.Contact.CustomName) that appears in an Inspector will cause GetCustomUI to be called. If you are only interested in customizing the Ribbon on Inspectors for your custom message class, note the following points.
You should return Ribbon XML in GetCustomUI for the Ribbon ID that represents the Inspector type for your custom message class, such as IPM.Contact.CustomName.
If you are only controlling the visibility of your custom Ribbon tabs, groups, and controls on your custom message class, call the InvalidateControl method on the IRibbonUI object in the NewInspector event. In the NewInspector event, evaluate whether Inspector.CurrentItem.MessageClass represents your custom message class. To improve performance, call the InvalidateControl method only on appropriate tabs, groups, and controls for your custom message class. Calling the InvalidateControl method in the NewInspector event causes GetVisible and other callbacks to be called every time an Inspector displays for your custom message class. For example, the following code in the NewInspector event shows this technique for the custom message class IPM.Contact.Shoe Store.
Visual Basic Example
Private Sub Inspectors_NewInspector(ByVal Inspector _
As Microsoft.Office.Interop.Outlook.Inspector) _
Handles m_Inspectors.NewInspector
Try
Dim olItem As New OutlookItem(Inspector.CurrentItem)
' Make Make sure this is an "IPM.Contact.Shoe Store" item
If olItem.MessageClass = "IPM.Contact.Shoe Store" Then
m_Ribbon.InvalidateControl("ShoeSizeGroup")
m_Ribbon.InvalidateControl("ShoeColorGroup")
End If
Catch ex As Exception
Debug.Write(ex.Message)
End Try
End Sub
private void Inspectors_NewInspector(Outlook.Inspector Inspector)
{
try
{
OutlookItem olItem = new OutlookItem(Inspector.CurrentItem);
// Make sure this is an "IPM.Contact.Shoe Store" item
if (olItem.MessageClass == "IPM.Contact.Shoe Store")
{
m_Ribbon.InvalidateControl("ShoeSizeGroup");
m_Ribbon.InvalidateControl("ShoeColorGroup");
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
}
If you are controlling the visibility of built-in Ribbon tabs, groups, and controls in addition to your custom Ribbon tabs, groups, and controls, call the Invalidate method on the IRibbonUI object in the NewInspector event. In the NewInspector event, evaluate whether Inspector.CurrentItem.MessageClass represents your custom message class before you call the Invalidate method. Calling the Invalidate method is expensive with regard to performance. Therefore, you should call this method only for the appropriate message class. Calling the Invalidate method in the NewInspector event causes GetVisible callbacks every time that an Inspector displays for your custom message class.
You should use GetVisible callbacks to control the visibility of your custom Ribbon tabs, groups, and controls. The IRibbonControl.Context object that is passed in the callback represents an Outlook Inspector object. After you have an Inspector object in the callback, use Inspector.CurrentItem.MessageClass to determine whether to return true or false in the GetVisible callback.
To customize the Ribbon on all or multiple Outlook message classes, consider the following recommendations:
To customize the first built-in tab on all Outlook Inspectors, supply separate Ribbon XML for different Ribbon IDs because built-in first tabs do not have the same name across all Ribbon IDs.
If you want to customize the Ribbon on multiple Outlook Inspectors, you might have to supply separate Ribbon XML for different Ribbon IDs depending on the tab name.
Now view GetCustomUI in the sample add-in that accompanies this article. Notice that customUI is stored as a resource in the add-in project. To supply Ribbon markup for more than one RibbonID, name your resources appropriately and return the correct resource in the GetCustomUI procedure. The following examples return the Ribbon markup for Color Widgets.
Visual Basic Example
Function GetCustomUI(ByVal RibbonID As String) As String _
Implements Microsoft.Office.Core.IRibbonExtensibility.GetCustomUI
Select Case RibbonID
Case "Microsoft.Outlook.Contact"
' Return the Ribbon extensibility markup stored as a resource.
Return My.Resources.customUI
End Select
Return String.Empty
End Function
C# Example
public string GetCustomUI(string ribbonID)
{
switch (ribbonID)
{
case "Microsoft.Outlook.Contact":
// Return the Ribbon extensibility markup stored as a resource.
string xmlMarkup = Properties.Resources.customUI;
return xmlMarkup;
default:
return String.Empty;
}
}
Detecting Errors
The Ribbon markup that you return in the GetCustomUI call usually contains callbacks that run when an Inspector is about to be displayed. For each callback in your Ribbon markup, you must add the callback to the add-in class that implements the IRibbonExtensibility interface. These callbacks must be declared as public procedures. If, for some reason, you omit a callback or use an incorrect callback signature, your Ribbon customization will fail silently unless you turn on error detection when you debug your solution.
To use error detection when your Ribbon markup is loaded, follow these steps to display the Advanced Options dialog box shown in Figure 5.
In an Outlook Explorer window, click the Toolsmenu, click Options, and then click the Other tab.
Click Advanced Options, and then check Show add-in user interface errors in the In all Office applications frame.
Click OK to save changes.
Figure 5. Advanced Options dialog box for reporting Ribbon markup errors
Note
If you select the Show add-in user interface errors check box, you turn on error reporting for all Office applications.
Note |
---|
If you select the Show add-in user interface errors check box, you turn on error reporting for all Office applications. |
NewInspector Event
After GetCustomUI is called and Ribbon markup is returned, your add-in should hook up the NewInspector event so that your code can track the state of the Inspector window. The sample add-in has a small example of state tracking. The Color Widgets group has a combo box control where the user can select Red, Green, or Blue as a color. If the user clicks the Color button control, a message box displays the selected color. This example is simple and demonstrates a problem that is common to implementing Ribbon controls on Outlook Inspectors. Outlook can display multiple Inspectors, and the user can switch context between these windows. For example, assume that in Inspector 1 the selected color is green and in Inspector 2 the selected color is red. The sample code can determine the selected color for a given Inspector by using the NewInspector event in combination with a wrapper class named OutlookInspector. Next, we will discuss how to write code in the NewInspector event, and then we can move on to a discussion of the OutlookInspector wrapper class.
In the Visual Basic sample add-in, the InitializeAddin procedure instantiates the m_Inspectors object dimensioned using the WithEvents keyword. In the Visual C# sample add-in, you hook up the NewInspector event on the m_Inspectors object. Here is the InitializeAddin procedure that is called from the IDTExtensibility2_OnConnection event.
Visual Basic Example
Private Sub InitializeAddin()
m_Inspectors = Application.Inspectors
m_Windows = New List(Of OutlookInspector)
End Sub
C# Example
private void InitializeAddin()
{
// Initialize variables.
m_Inspectors = Application.Inspectors;
m_Windows = new List<OutlookInspector>();
// Wire up event handlers.
m_Inspectors.NewInspector +=
new Outlook.InspectorsEvents_NewInspectorEventHandler(
Inspectors_NewInspector);
}
Besides hooking up the NewInspector event handler in InitializeAddin, an instance variable named m_Windows is created that acts as a generic List class for OutlookInspector objects. A List class represents a strongly typed list of objects that can be accessed by index and provides methods to search, sort, and manipulate lists.
Next, we look at the NewInspector event procedure. Because we are only interested in Inspectors for contact items, the code first evaluates if Inspector.CurrentItem.Class equals olContact. If we have a contact item, FindOutlookInspector tries to find a given Inspector window in the m_Windows List. If the existingWindow is null (Nothing in Visual Basic), a new instance of OutlookInspector is created for the Inspector, and that class instance is added to m_Windows.
Visual Basic Example
Private Sub Inspectors_NewInspector(ByVal Inspector _
As Microsoft.Office.Interop.Outlook.Inspector) _
Handles m_Inspectors.NewInspector
Dim olItem As New OutlookItem(Inspector.CurrentItem)
' Make sure this is a contact item
If olItem.Class = Outlook.OlObjectClass.olContact Then
' Check to see if this is a new window not already tracked
Dim existingWindow As OutlookInspector = _
FindOutlookInspector(Inspector)
If existingWindow Is Nothing Then
Dim window As OutlookInspector = _
New OutlookInspector(Inspector)
' Listen to the window.Close event
AddHandler window.Close, AddressOf WrappedWindow_Close
' Listen to the window.InvalidateControl event
AddHandler window.InvalidateControl, _
AddressOf WrappedWindow_InvalidateControl
m_Windows.Add(window)
End If
End If
End Sub
C# Example
private void Inspectors_NewInspector(Outlook.Inspector Inspector)
{
try
{
OutlookItem olItem = new OutlookItem(Inspector.CurrentItem);
// Make sure this is a contact item
if (olItem.Class == Outlook.OlObjectClass.olContact)
{
// Check to see if this is a new window
// we don't already track
OutlookInspector existingWindow =
FindOutlookInspector(Inspector);
// If the m_Windows collection does not
// have a window for this Inspector,
// we should add it to m_Windows
if (existingWindow == null)
{
OutlookInspector window =
new OutlookInspector(Inspector);
window.Close += new EventHandler(WrappedWindow_Close);
window.InvalidateControl += new EventHandler<
OutlookInspector.InvalidateEventArgs>(
WrappedWindow_InvalidateControl);
m_Windows.Add(window);
}
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
}
OutlookInspector Class
The OutlookInspector class wraps an Inspector object. Each instance of this class enables you to track the state of a given Inspector window. The following functions are provided by the OutlookInspector class:
Wraps each instance of an Inspector object
Provides Open, Close, and PropertyChange events for the wrapped Inspector's CurrentItem, which in this case is a ContactItem
Exposes Properties so that callbacks in the Connect class or the OutlookRibbonXVB or OutlookRibbonXCS class (VSTO 2005 examples) can set or get properties such as RibbonColor
Let me explain a bit more of the business logic of the Outlook Ribbon extensibility sample add-in. The visibility of the Color Widgets group depends on the existence of a mailing address in the ContactItem displayed in the Inspector. If a given contact has a business, home, or other address, the Color Widgets group appears on the Ribbon. If the contact has no business, home, or other address, the Color Widgets group does not appear on the Ribbon. If the state of the contact changes (for example, the user adds a business address to a new contact), the PropertyChange event detects that change and causes controls on the Ribbon to be invalidated. After the Ribbon control is invalidated, the callbacks for that control will be called again.
IRibbonUI Object
The IRibbonUI object represents all the Ribbon controls that are defined by your add-in. You specify a callback in your Ribbon markup (see an example of the <customUI> tag in the section "Authoring Custom XML"). This callback provides an IRibbonUI object that you can use to invalidate all controls defined by your add-in or a single control specified by name. IRibbonUI is scoped to your add-in. If you call the IribbonUI methods, they apply only to your add-in instead of all connected add-ins in Outlook. Here is the Ribbon_OnLoad callback in the sample add-in.
Visual Basic Example
Public Sub Ribbon_OnLoad(ByVal ribbon As Office.IRibbonUI)
m_Ribbon = ribbon
End Sub
C# Example
public void Ribbon_OnLoad(Office.IRibbonUI ribbon)
{
m_Ribbon = ribbon;
}
IRibbonUI exposes the following methods.
Table 4. Methods exposed by IRibbonUI
Method |
Action |
Description |
---|---|---|
Invalidate() |
callback |
Marks all the custom controls in your add-in for update |
InvalidateControl(string controlID) |
callback |
Marks a specific control defined by controlID in your add-in for update |
For performance reasons, a best practice when you use the IRibbonUI object is to call InvalidateControl instead of Invalidate. If you call Invalidate, all Ribbon controls defined by your add-in are invalidated and callbacks will occur on open Inspectors. Note that the instance variable that represents IRibbonUI is m_Ribbon. This instance variable is defined in the Connect class. To call m_Ribbon.InvalidateControl from the OutlookInspector class when the PropertyChange event detects that the ColorWidgetsGroup requires invalidation because of an address change, the RaiseInvalidateControl procedure is called in OutlookInspector. This procedure raises the InvalidateControl event in the OutlookInspector class, which is handled by the WrappedWindow_InvalidateControl event procedure in the Connect class.
Visual Basic Example
Private Sub WrappedWindow_InvalidateControl( _
ByVal sender As Object, _
ByVal e As OutlookInspector.InvalidateEventArgs)
If Not (m_Ribbon Is Nothing) Then
m_Ribbon.InvalidateControl(e.ControlID)
End If
End Sub
C# Example
void WrappedWindow_InvalidateControl(object sender,
OutlookInspector.InvalidateEventArgs e)
{
if (m_Ribbon != null)
{
m_Ribbon.InvalidateControl(e.ControlID)
}
}
IRibbonControl Object
The IRibbonControl object is passed in most of the callbacks available for Ribbon controls. This object is especially useful for Outlook developers because it provides a Context object that represents the Outlook Inspector object that is about to be displayed.
IRibbonControl exposes the following properties.
Table 5. Properties exposed by IRibbonControl
Property |
Type |
Description |
---|---|---|
Context |
Object |
Read-only. Returns an object that represents the window where the Ribbon is about to be displayed. |
Id |
String |
Read-only. Returns a string that represents the id attribute for the control. |
Tag |
String |
Read-only. Returns a string that represents the tag attribute for the control. |
To understand how to use the Context object and cast it to an Outlook Inspector, consider the following code examples. First, look at the ColorWidgetsGroup_GetVisible callback in the Connect class. This callback occurs when a contact Inspector window is created or an existing Inspector window is opened. Control.Context is passed to the FindOutlookWindow procedure and ensures that the code examines the state of the correct ContactItem. By using our simple business logic, the callback returns true if the item has an address or false if the item does not have an address. Returning true makes the ColorWidgetsGroup control visible and returning false hides the control.
Visual Basic Example
Public Function ColorWidgetsGroup_GetVisible( _
ByVal control As Office.IRibbonControl) As Boolean
Dim window As OutlookInspector = _
FindOutlookInspector(control.Context)
If Not window Is Nothing Then
Dim contact As Outlook.ContactItem = window.CurrentItem
' Make the group visible only if an address exists.
If String.IsNullOrEmpty(contact.BusinessAddress) _
And String.IsNullOrEmpty(contact.HomeAddress) _
And String.IsNullOrEmpty(contact.OtherAddress) Then
Return False
Else
Return True
End If
End If
Return False
End Function
C# Example
public bool ColorWidgetsGroup_GetVisible(Office.IRibbonControl control)
{
OutlookInspector window = FindOutlookInspector(control.Context);
if (window != null)
{
Outlook.ContactItem contact = window.CurrentItem;
// Make the group visible only if an address exists.
if (String.IsNullOrEmpty(contact.BusinessAddress) &
String.IsNullOrEmpty(contact.HomeAddress) &
String.IsNullOrEmpty(contact.OtherAddress))
{
return false;
}
else
{
return true;
}
}
return false;
}
When the Color button is clicked on the Color Widgets group, the ColorButton_Action callback defined for the ColorButton control is called. It is also helpful to examine how the IRibbonControl.Context object is used in this callback. In this callback, the FindOutlookWindow procedure returns the Inspector where the color button was clicked. In the ColorButton_Action procedure, Window.RibbonColor returns the selected color for that Inspector window and the selected color is displayed in a message box. How does the RibbonColor property of the OutlookInspector class know the correct selected color in Color Widgets? When the ColorCombo_OnChange callback is called, Window.RibbonColor is set for a specific instance of OutlookInspector.
Visual Basic Example
Public Sub ColorButton_Action(ByVal control As Office.IRibbonControl)
Try
Dim window As OutlookInspector = _
FindOutlookInspector(control.Context)
If Not window Is Nothing Then
MessageBox.Show(My.Resources.AlertMessage _
& window.RibbonColor, _
My.Resources.Ribbon_ColorWidgetsGroup, _
MessageBoxButtons.OK, MessageBoxIcon.Information)
End If
Catch ex As Exception
Debug.WriteLine(ex.Message)
End Try
End Sub
C# Example
public void ColorButton_Action(Office.IRibbonControl control)
{
try
{
OutlookInspector window = FindOutlookInspector(control.Context);
if (window != null)
{
MessageBox.Show(Properties.Resources.AlertMessage +
window.RibbonColor,
Properties.Resources.Ribbon_ColorWidgetsGroup,
MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
}
VSTO 2005 SE and the Ribbon
You can use VSTO 2005 SE to add a Ribbon item to your Outlook 2007 add-in project. For the Outlook Ribbon extensibility VSTO add-ins, the name of the Ribbon item is OutlookRibbonXCS or OutlookRibbonXVB. When VSTO creates the Ribbon item, it provides boilerplate code that you must remove the comment marks from to hook up your Ribbon. The boilerplate code is uncommented in the sample VSTO add-ins and modified slightly so that you pass a trusted Outlook.Application object from the ThisAddin class to the constructor for the class that implements the Ribbon. This approach enables you to use the trusted Application object in your code in the Ribbon class so that your add-in will not display the Outlook object model guard security dialog box if your Ribbon code accesses a protected member. The following code example shows the modified code for the override of the RequestService method.
Visual Basic Example
Partial Public Class ThisAddIn
Private ribbon As OutlookRibbonXVB
Protected Overrides Function RequestService( _
ByVal serviceGuid As Guid) As Object
If serviceGuid = GetType(Office.IRibbonExtensibility).GUID Then
If ribbon Is Nothing Then
ribbon = New OutlookRibbonXVB(Application)
End If
Return ribbon
End If
Return MyBase.RequestService(serviceGuid)
End Function
End Class
C# Example
public partial class ThisAddIn
{
private OutlookRibbonXCS ribbon;
protected override object RequestService(Guid serviceGuid)
{
if (serviceGuid == typeof(Office.IRibbonExtensibility).GUID)
{
if (ribbon == null)
ribbon = new OutlookRibbonXCS(Application);
return ribbon;
}
return base.RequestService(serviceGuid);
}
}
The constructor for the OutlookRibbonXVB and OutlookRibbonXCS classes is straightforward. You define an instance variable for the Outlook.Application object at the class level, and then assign this instance variable in the constructor as shown in the following code example.
Visual Basic Example
[Visual Basic]
<ComVisible(True)> _
Public Class OutlookRibbonXVB
Implements Office.IRibbonExtensibility
Dim Application As Outlook.Application
Public Sub New(ByVal outlookApplication As Outlook.Application)
Application = outlookApplication
End Sub
' Additional code here
End Class
C# Example
[ComVisible(true)]
public class OutlookRibbonXCS : Office.IRibbonExtensibility
{
private Outlook.Application Application;
public OutlookRibbonXCS(Outlook.Application outlookApplication)
{
Application = outlookApplication;
}
// Additional code here
}
For the most part, the code in the OutlookRibbonXVB and OutlookRibbonXCS classes is the same as the code discussed earlier in this article. However, there is one important difference that you should understand. The m_Windows and m_Ribbon instance variables and the FindOutlookInspector method are defined in the ThisAddin class. For m_Windows, m_Ribbon, and FindOutlookInspector to be accessed from the Ribbon class, m_Windows, m_Ribbon, and FindOutlookInspector must be declared as FriendShared (Visual Basic) or internalstatic (C#) by using the following code.
Visual Basic Example
[Visual Basic]
Friend Shared m_Windows As List(Of OutlookInspector)
Friend Shared m_Ribbon As Office.IRibbonUI
Friend Shared Function FindOutlookInspector( _
ByVal window As Object) As OutlookInspector
For Each inspector As OutlookInspector In m_Windows
If inspector.Window Is window Then
Return inspector
End If
Next
Return Nothing
End Function
C# Example
[C#]
internal static List<OutlookInspector> m_Windows;
internal static Office.IRibbonUI m_Ribbon;
internal static OutlookInspector FindOutlookInspector(object window)
{
foreach (OutlookInspector inspector in m_Windows)
{
if (inspector.Window == window)
{
return inspector;
}
}
return null;
}
Conclusion
The Ribbon offers a compelling new UI for Outlook 2007 Inspector windows. If your existing Outlook solution uses command bar customizations in an Inspector, you should consider modifying your code to support the improved controls of the Ribbon. Ribbon extensibility in Outlook differs from other Office applications that extend the Ribbon by using an add-in. By using the techniques demonstrated in the sample Outlook Ribbon extensibility add-in, you can implement the Ribbon so that state changes in Outlook items are reflected in Ribbon controls.
Additional Resources
For more information about how to customize the 2007 Office system UI, see the following resources.