Pieter van der Westhuizen

How to dynamically bind Outlook add-in UI elements to the context

Something that I’ve noticed is that if you want to really start bending Microsoft Outlook to your programming will, you need to start embracing and combining the use of message classes and content types when developing Outlook add-ins.

If you’ve been using Add-in Express for a while or have read through our website and relevant blogs in the past, you’ll surely know that Add-in Express has a very useful feature we call Outlook Context Sensitivity. This allows you to display (or hide) your own custom UI elements as well as a certain number of the built-in Outlook UI elements.

In this article we’ll dive into some real-world examples and I’ll show you how to truly integrate your solutions into Microsoft Office using Add-in Express for Office and .net.

Creating a new Outlook add-in project

Let’s start by creating a new ADX COM Add-in in Visual Studio 2012 (Add-in Express works with all versions and editions of Visual Studio starting from VS 2005).

Creating a new Outlook add-in project in Visual Studio 2012

When the New Microsoft Office COM Add-in Wizard starts, select your programming language of choice (C#, VB.NET or C++) and the minimum version of Microsoft Office your add-in needs to support.

Selecting a programming language of choice and the minimum Office version

Lastly, you can choose all the Microsoft Office applications you want your add-in to support. Since we want to have a look at Outlook context sensitivity, we’ll only choose Microsoft Outlook in the list for this instance.

Choosing Microsoft Outlook as the only Office application for your add-in to support

Once the wizard finishes, double-click the AddinModule.cs file to open its visual designer surface.

Project scenario – CRM add-in for Outlook

For this example, we’ll assume we need to create an in-house CRM (Customer Relationship Management) add-in for Microsoft Outlook. The system will contain a list of our customers as well as tasks associated with them. We’ll also assume that each user of the system would like to have their own Outlook contacts and tasks separate from the CRM systems’ contacts and tasks.

So, with our design brief in hand, let’s get started building this add-in.

Adding a solution module as a container for custom Outlook items

It would be ideal if the CRM system has its own pane/button in the Outlook navigation pane. Since Office 2010, developers were able to accomplish this by using the Solutions Module. Add-in Express improved on this and made it even easier by providing us with a Solutions Module component which gives us a graphical designer in order to add our own solutions module.

To add one, simply click on the ADXOLSolutionsModule button and it will be added to the design surface of your AddinModule.

Adding a solution module

Next, select the newly created ADXOLSolutionsModule component and click the ellipses (…) button next to its Folders property.

Configuring the Solution Module component

A visual designer will be shown, with which you can add folders to the Solutions Module. The FolderName property of the first item will be displayed in the Outlook Navigation pane. The Solution Module design for our sample application looks similar to the following image:

The Solution Module design

You’ll notice that you can specify which type of Outlook item the folder should have by using the FolderType property. I’ve set the Customers folder’s FolderType property to Contacts and the Task folders’ to Tasks, which means that the folder Message class would be IPM.Contact and IPM.Task respectively.

Changing the folders’ default Message class to be able to dynamically alter the Outlook UI

All contact items in Outlook share the same message class which is IPM.Contact, but I want to give my CRM systems’ contact items their own Message class, which will enable me to dynamically alter the Outlook UI later.

I’ve written a method that will find a folder and change its Message class, the code for the method would be as follows:

private void FindFolderAndSetMessageClass(string folderPath,
    string messageClass, string displayName)
{
    Outlook.Folder foundFolder = null;
    Outlook.Folders subFolders = null;
    Outlook.NameSpace session = null;
    Outlook.Folders sessionFolders = null;
    Outlook.PropertyAccessor folderPropertyAccessor = null;
 
    try
    {
        session = OutlookApp.Session;
        folderPath = folderPath.TrimStart("\\".ToCharArray());
 
        String[] folders = folderPath.Split("\\".ToCharArray());
        sessionFolders = session.Folders;
        foundFolder = sessionFolders[folders[0]] as Outlook.Folder;
 
        if (foundFolder != null)
        {
            String folderName;
            for (int i = 1; i < folders.Length; i++)
            {
                folderName = folders[i];
                subFolders = foundFolder.Folders;
                foundFolder = subFolders[folderName] as Outlook.Folder;
            }
            folderPropertyAccessor = foundFolder.PropertyAccessor;
 
            folderPropertyAccessor.SetProperty(
                "https://schemas.microsoft.com/mapi/proptag/0x36E5001E", messageClass);
            folderPropertyAccessor.SetProperty(
                "https://schemas.microsoft.com/mapi/proptag/0x36E6001E", displayName);
        }
    }
    finally
    {
        if (folderPropertyAccessor != null)
            Marshal.ReleaseComObject(folderPropertyAccessor);
        if (sessionFolders != null)
            Marshal.ReleaseComObject(sessionFolders);
        if (session != null)
            Marshal.ReleaseComObject(session);
        if (subFolders != null)
            Marshal.ReleaseComObject(subFolders);
        if (foundFolder != null)
            Marshal.ReleaseComObject(foundFolder);
    }
}

In order to change the Message classes of the Customers and Tasks folders of the Solutions Module, we need to run the following method:

private void SetSMFolderMessageClasses()
{
    Outlook.NameSpace session = null;
    Outlook.Store defaultStore = null;
    Outlook.Folder rootFolder = null;
 
    try
    {
        session = OutlookApp.GetNamespace("MAPI");
        defaultStore = session.DefaultStore;
        rootFolder = defaultStore.GetRootFolder() as Outlook.Folder;
        FindFolderAndSetMessageClass(
            String.Format("{0}\\Northwind CRM\\Customers", rootFolder.FolderPath),
            "IPM.Contact.NorthwindCRM.Customer", "Northwind Customer");
        FindFolderAndSetMessageClass(
            String.Format("{0}\\Northwind CRM\\Tasks", rootFolder.FolderPath),
            "IPM.Task.NorthwindCRM.Task", "Northwind Task");
    }
    finally
    {
        if (rootFolder != null)
            Marshal.ReleaseComObject(rootFolder);
        if (defaultStore != null)
            Marshal.ReleaseComObject(defaultStore);
        if (session != null)
            Marshal.ReleaseComObject(session);
    }
}

Creating your own Outlook UI: ribbon tab and custom form

When a user opens a Northwind Customer in Outlook, we want to show them the standard Outlook Contact form as well as an additional form that displays CRM specific information and options.

To do this we'll first need to add an ADXOLFormsManager component to the AddinModule designer surface.

Adding an ADXOLFormsManager component to the AddinModule designer surface

Next, add a new Outlook Form to your project.

Adding a new Outlook Form to your project

Switch back to the AddinModule designer and select the Forms Manager component we've added earlier. Add a new item to its item collection and set the following properties:

  • FormClassName : OutlookContextExample.NorthwindCustomerForm
  • InspectorLayout : InspectorRegion
  • InspectorMessageClass : IPM.Contact.NorthwindCRM.Customer

While we have the AddinModule designer open, let's add a CRM system specific RibbonTab control.

Adding a RibbonTab control

Set the Ribbon Tabs' Ribbons property to OutlookContact. The design for the custom Outlook Ribbon tab can resemble the following image:

The design for the custom Outlook Ribbon tab

We only want the Ribbon Tab to be visible when the user opens a contact item in the Northwind Customers folder and it should not be visible for any other contact item. To do this we first need to add an OutlookAppEvents component to the AddinModule designer surface.

Adding an OutlookAppEvents component to the AddinModule designer surface

Add a new event handler for the NewInspector event and add the following code to it:

private void adxOutlookEvents_NewInspector(object sender,
    object inspector, string folderName)
{
    Outlook.Inspector currInsp = null;
    Outlook.ContactItem contact = null;
 
    try
    {
        currInsp = (Outlook.Inspector)inspector;
        if (currInsp.CurrentItem is Outlook.ContactItem)
        {
            contact = currInsp.CurrentItem as Outlook.ContactItem;
 
            if (contact.MessageClass == "IPM.Contact.NorthwindCRM.Customer")
            {
                northwindCustomerRibbonTab.Visible = true;
            }
            else
            {
                northwindCustomerRibbonTab.Visible = false;
            }
 
            if (theRibbonUI != null)
            {
                theRibbonUI.InvalidateControl(
                    "northwindCustomerRibbonTab_5b0ccb59fdfa49b0a601bca0da52c15b");
            }
        }
    }
    finally
    {
        if (contact != null)
            Marshal.ReleaseComObject(contact);
    }
}

theRibbonUI is a class-level variable that I declared earlier:

IRibbonUI theRibbonUI;

The InvalidateControl method needs to be passed the Id property of the Ribbon Tab you would like to invalidate.

Next, add an event handler for the OnRibbonLoaded event and add the following code:

private void AddinModule_OnRibbonLoaded(object sender, IRibbonUI ribbon)
{
    theRibbonUI = ribbon;
}

With the code in place, you can build and register your Outlook plugin and when the user creates or opens a contact item in the Northwind Customers folder they should see our custom Outlook region and Ribbon tab.

The custom form and Ribbon tab bound to a specific Contact folder

When the user opens a standard Outlook contact the Ribbon Tab and custom region will not be visible. You'll also notice that the New Contact button will display the text we've set the property to, because we've set the https://schemas.microsoft.com/mapi/proptag/0x36E6001E earlier, e.g.:

The customized native Outlook 'New Contact' button

Thank you for reading. Until next time, keep coding!

Available downloads:

This sample Outlook add-in was developed using Add-in Express for Office and .net:

C# Outlook context sensitive add-in

You may also be interested in:

2 Comments

  • Abhinav Mathur says:

    Hi Pieter,

    We have a similar outlook Add In provided by Oracle for accessing Siebel CRM data in Outlook. This COM Addin creates folders for CRM accounts, opportunities, activities data which are basically built from Outlook’s standard Contact form.
    The message class are named as IPM.Contact.SBL.Account, IPM.Contact.SBL.Opportunity respectively. Here when I navigate to Opportunity folder, the New Contact button will display the text “New Opportunity” similar to your example.
    Now we have a requirement to disable this “New Opportunity” button which is controlled by Outlook’s native ribbon control so that users are not able to create new opportunities in Outlook. Could you please provide a sample code or any helpful document to do the same.

  • Pieter van der Westhuizen says:

    Hi Abhinav,

    What I suggest you do is to replace the standard “New” group of the Contacts Tab with your own, and add the standard controls to this group.
    You can then hide/show the “New Opportunity” button based on the MessageClass or name of the current folder. For example, any folder with a message class of IPM.Contact.SBL.Opportunity, will not have a New opportunity button.

    I’ve created a simple sample add-in for you. It adds an “EXAMPLE” tab to the Outlook Explorer, click the “Create Test Folder” button and it will create a folder called “EXAMPLE”. This folder will have a messageclass of IPM.Contact.Opportunity. See the code on how to hide/show the New button. You can download the sample here.

    Hope this helps and good luck!

Post a comment

Have any questions? Ask us right now!