Automating Search Highlighting in Outlook 2010

Office Visual How To

Summary:  Learn how to use the Microsoft Word object model in a C# Microsoft Outlook 2010 add-in to extend Outlook Instant Search and highlight the search term in an item displayed in an inspector.

Applies to: Office 2010 | Outlook 2010 | Visual Studio | Word 2010

Published:  April 2011

Provided by:  Jonathan Fingold, SDK Bridge LLC | Angela Chu-Hatoun, Microsoft Corporation

Overview

This Visual How To describes a search highlighting add-in for Microsoft Outlook 2010 that uses the Outlook Instant Search feature to find items that contain a search term, and then uses the Word object model to open an Outlook item in an inspector and highlight the search term. This Visual How To describes what the tool does and explains the add-in code. This Visual How To also describes some associated extensibility features of the ribbon component of the Microsoft Office Fluent user interface (UI).

The sample that accompanies this Visual How To uses a C# Outlook add-in project written in Visual Studio 2010 and assumes that you are already familiar with C# and creating add-ins for Outlook.

Code It

When you perform an Instant Search, Outlook highlights the search term in the explorer and Reading Pane, but it does not highlight the search term in the item when the item is opened in an inspector. There are two main aspects to the add-in code. First, the add-in uses the ribbon extensibility features of Outlook to provide custom UI to open and highlight an item that is returned in the explorer as a search result from a folder-level search. Second, it uses the Word object model to highlight occurrences of a search term in an Outlook item opened in an inspector.

Defining the Custom Ribbon UI

The custom ribbon UI for the add-in is described in the SearchRibbon.xml file. It adds a Custom Search group to the Home tab for mail items. The control ID for the mail item Home tab is TabMail.

Figure 1. Custom Search group on the ribbon UI

Custom Search group on the ribbon UI

A benefit of adding the custom search UI to the Home tab for mail items is that the custom search UI is available only when the user is viewing a mail folder.

The following code adds the Custom Search tab to the ribbon.

<tabs>
    <tab idMso="TabMail">
        <group id="CustomSearch" label="Custom Search">

Inside the Custom Search group, the add-in declares an onChange event handler and a getText callback method for the search text box, and an onAction event handler for the Open Message with Highlights button, as shown in the following code. The event handlers and callback method allow the add-in code to interact with the ribbon UI. The names that are shown in the following code reference methods that are defined in the custom ribbon code.

The add-in does not declare an event handler for the Search button. The Search button is provided as a UI clue for the user, because the text box does not raise the onChange event until the user presses Enter or the text box loses focus.

<box id="SearchControls">
    <editBox id="SearchEditBox" screentip="Enter search text"
               label="Search for:" showLabel="true" maxLength="64"
               onChange="TextChanged" getText="GetText"/>
        <button id="SearchButton" label="Search" showLabel="false"
                imageMso="AllModuleNameItems" showImage="true"
                visible="true"/>
    </box>
    <button id="OpenMessageButton" label ="Open Message with Highlights"
            screentip="Opens the selected message"
            onAction="OpenMessage"/>
</group>

For more information about declaring custom ribbon UI, see the three-part article, Customizing the 2007 Office Fluent Ribbon for Developers.

Handling Outlook and Ribbon UI Events

The SearchRibbon class defines the event handlers and the callback method for the custom ribbon UI. To support some of the functionality that is associated with these methods, when the SearchRibbon class loads, the class saves a reference to the associated ribbon UI object. All ribbon UI objects implement the IRibbonUI interface. The class also updates the static ribbonUI field of the ThisAddIn class by using a reference to the ribbon UI object.

The following code is from the SearchRibbon class.

/// <summary>A reference to the custom ribbon UI object.</summary>
private Office.IRibbonUI ribbonUI;

/// <summary>The cached search term.</summary>
internal string currentSearchText = string.Empty;

//...

public void Ribbon_Load(Office.IRibbonUI ribbonUI)
{
    ThisAddIn.ribbonUI = ribbonUI;
    this.ribbonUI = ribbonUI;
}

The ribbon XML references a getText callback method, GetText, and an onChange event handler, TextChanged. When the user enters new text in the text box, the ribbon UI notifies the add-in by calling the referenced method (in this case, TextChanged). The TextChanged method validates the search term, and then calls the Search(String, OlSearchScope) method of the active Explorer object. The Search method performs an Instant Search on the current folder that is displayed in the explorer. The add-in restricts the search to include only the current folder by setting the SearchScope parameter to the olSearchScopeCurrentFolder value of the OlSearchScope enumeration.

Outlook automatically opens the Search Tools tab when it performs an Instant Search, so the add-in opens the Home tab after the call to the Search method. The custom ribbon code also caches the search term in the currentSearchText instance field of the custom ribbon class.

Whenever Outlook updates the custom ribbon UI for the add-in, the ribbon UI calls the text box control's getText callback method, GetText, to get the correct text.

The following code is from the SearchRibbon class and contains the definitions for the TextChanged and GetText methods.

/// <summary>Handles the onChange event of the CustomSearch text box.
/// </summary>
/// <param name="control">The source of the event.</param>
/// <param name="text">The updated text of the text box.</param>
public void TextChanged(Office.IRibbonControl control, string text)
{
    Outlook.Explorer explorer = ActiveExplorer;
    if (string.IsNullOrWhiteSpace(text))
    {
        currentSearchText = null;
        explorer.ClearSearch();
    }
    else
    {
        currentSearchText = text.Trim();

        explorer.Search(currentSearchText,
            Outlook.OlSearchScope.olSearchScopeCurrentFolder);

        ribbonUI.ActivateTabMso("TabMail");
    }
}

/// <summary>Handles the getText callback of the CustomSearch text box.
/// </summary>
/// <param name="control">The source control of the callback.</param>
/// <returns>The text to place in the text box control.</returns>
public string GetText(Office.IRibbonControl control)
{
    return currentSearchText;
}

When the user changes folders, the add-in clears the custom search. To do so, the add-in registers for the FolderSwitch event of the Explorer object.

The add-in registers for the FolderSwitch event in its startup event handler and unregisters from the event in its shutdown event handler. In the explorer_FolderSwitch method, which handles the folder switch event for the add-in, the add-in clears the custom ribbon's search term and then calls the Invalidate() method of the ribbon UI object. This causes Outlook to refresh the custom ribbon UI for the add-in. When the ribbon UI updates, it calls the text box control's getText callback method, GetText, to get the correct text.

The following code is from the ThisAddIn class.

private Outlook.Explorer explorer;

/// <summary>Handles the startup event of the add-in.</summary>
/// <remarks>Subscribes to the folder switch event of the active
/// explorer.</remarks>
private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
    explorer = Application.ActiveExplorer();
    explorer.FolderSwitch +=
        new Outlook.ExplorerEvents_10_FolderSwitchEventHandler(
            explorer_FolderSwitch);
}

/// <summary>Handles the shutdown event of the add-in.</summary>
/// <remarks>Unsubscribes from the folder switch event.</remarks>
private void ThisAddIn_Shutdown(object sender, System.EventArgs e)
{
    explorer.FolderSwitch +=
        new Outlook.ExplorerEvents_10_FolderSwitchEventHandler(
            explorer_FolderSwitch);
    explorer = null;
    ribbonUI = null;
}

/// <summary>Handles the folder switch event of an explorer.</summary>
void explorer_FolderSwitch()
{
    // Set the Search string.
    if (ribbon.SearchText != null && ribbon.SearchText != string.Empty)
    {
        ribbon.SearchText = string.Empty;
        if (ribbonUI != null)
        {
            ribbonUI.Invalidate();
        }
    }
}

Selecting an Outlook Item from the Explorer Selection

When the user clicks Open Message with Highlighting, the user may have selected several items in the explorer. In the event handler for the button, the add-in iterates through the selected items and displays the first item that is either a MailItem object or a MeetingItem object, and then calls the FindInInspector helper method to highlight the search term.

The OpenMessage method is defined in the SearchRibbon class, as shown in the following code.

/// <summary>Handles the onAction event of the OpenMessage button.
/// </summary>
/// <param name="control">The source control of the event.</param>
public void OpenMessage(Office.IRibbonControl control)
{
    if (!string.IsNullOrWhiteSpace(currentSearchText))
    {
        // Obtain a reference to the selection.
        Outlook.Selection selection = ActiveExplorer.Selection;
        if (selection.Count == 0) return;

        // Open the first item that is a supported Outlook item.
        // The selection may contain various item types.
        IEnumerator e = ActiveExplorer.Selection.GetEnumerator();
        while (e.MoveNext())
        {
            if (e.Current is Outlook.MailItem)
            {
                Outlook.MailItem item = e.Current as Outlook.MailItem;
                item.Display();
                FindInInspector(item.GetInspector, currentSearchText);
                break;
            }
            else if (e.Current is Outlook.MeetingItem)
            {
                Outlook.MeetingItem item =
                    e.Current as Outlook.MeetingItem;
                item.Display();
                FindInInspector(item.GetInspector, currentSearchText);
                break;
            }
        }
    }
}

Highlighting a Search Term in an Open Item

As shown in the following code, the add-in project contains a reference to the Microsoft.Office.Interop.Word assembly, and the SearchRibbon.cs file has a using directive to create an alias for the Microsoft.Office.Interop.Word namespace. When the add-in opens an Outlook item, it uses the Word object model to perform the highlighting within the opened message.

Note

The major version number for the Word 2010 interop assembly is version 14, and some methods that are used in this add-in are not supported in earlier versions of the Word interop assemblies.

using System;
using System.Collections;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
using Office = Microsoft.Office.Core;
using Outlook = Microsoft.Office.Interop.Outlook;
using Word = Microsoft.Office.Interop.Word;

namespace SearchHighlighting
{
    [ComVisible(true)]
    public class SearchRibbon : Office.IRibbonExtensibility
    {

The add-in defines a FindInInspector helper method to highlight the search term in an Outlook Inspector object. The method uses a Find object to perform the highlighting in the inspector for the search term.

The FindInInspector method uses the following steps to highlight the search term in the inspector.

  1. The method exits if the Inspector object or the search term is invalid. The IsWordMail() method of the inspector indicates whether the inspector is displaying the item's contents within the Word editor.

    Note

    Beginning with Outlook 2007, Outlook supports the Word editor only for email items.

  2. The add-in uses the inspector's WordEditor property to get the Word Document object for the Outlook item that is open in the inspector.

    The Document object represents only the body, and does not include the subject of an email message or meeting item. Instant Search and Explorer.Search return as a search result any item where the search term occurs in the subject or body of the item. However, opening and searching the item based on the Document object does not highlight occurrences of the search term in the subject of the item.

  3. The add-in gets from the document a Range object.

    1. The Word document's Application property returns the Word Application object for the document.

    2. The Word application's Selection property returns a Selection object for the document.

    3. And, the selection's Range property returns a Range object for the selection.

  4. The add-in uses the Find property of the Range object to get a Find object, and then calls that object's HitHighlight(Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object) method to perform the highlighting for the search term.

    Note

    When there is no selection in the inspector, as is the case when the item is first displayed, the Find object searches the whole document.

As shown in the following code, the FindInInspector method is defined in the SearchRibbon class.

/// <summary>Performs search highlighting in an open mail item.
/// </summary>
/// <param name="inspector">The inspector for the open item.</param>
/// <param name="searchText">The text to highlight.</param>
private void FindInInspector(Outlook.Inspector inspector, string term)
{
    if (inspector == null || string.IsNullOrWhiteSpace(term)) return;

    if (inspector.IsWordMail())
    {
        Word.Document doc = inspector.WordEditor as Word.Document;

        Word.Range wdRange = doc.Application.Selection.Range;

        Word.Find wdFind = wdRange.Find;
        wdFind.Format = false;
        wdFind.MatchCase = false;
        wdFind.MatchWholeWord = false;

        wdFind.HitHighlight(term,
            HighlightColor: Word.WdColor.wdColorYellow);
    }
}
Read It

When a user performs an Instant Search within Outlook, Outlook highlights the found text in the Reading Pane. However, when the user opens an item from the explorer, the inspector does not highlight the text that you had searched on (as shown in Figure 2).

Figure 2. Outlook item opened from the explorer

Outlook item opened from the explorer

Fortunately, the add-in can use the Word object model to add highlighting to the Outlook item when it is opened.

To keep this example simple, the add-in adds a Custom Search group to the Home tab for mail items, as shown in Figure 3. The Custom Search group includes a text box in which to enter a search term and an Open Message with Highlights button that opens the first applicable selected item in the current mail folder.

Figure 3. Custom Search group on the ribbon UI

Custom Search group on the ribbon UI

When the user opens an item with the Open Message with Highlights button, the add-in highlights all occurrences of the search term (as shown in Figure 4).

Figure 4. Outlook item opened from the Custom Search UI

Outlook item opened from the Custom Search UI
See It

Watch the video

> [!VIDEO https://www.microsoft.com/en-us/videoplayer/embed/719b0061-7725-4103-9891-630e57071b45]

Length: 5:59

Click to grab code

Grab the Code

Explore It