Customize Outlook Navigation Pane
with .NET forms: VB.NET, C#

Add-in Express™ Regions
for Microsoft® Outlook and VSTO


Customizing Outlook Navigation Pane

Add-in Express Regions allows adding .NET forms into 23 layouts of Outlook windows. This example demonstrates how to embed your custom .NET form under the Outlook Navigation pane using Visual Studio.

Once you have Add-in Express Regions installed, it's very easy to get started integrating Outlook Regions into your VSTO project. Let's start right from the beginning - start Visual Studio and create a new Outlook 2010 Add-in Project (if you like, you can choose an Outlook 2007 Add-in; no references specific to the 2010 Object Model are used in the following examples):

For this demonstration we're going to build an add-in that will highlight how to implement View Regions and show how useful they can be for designing creative Outlook solutions. We'll create two different View Regions:

  • Navigation Pane region that displays a list of recently received emails, it is described further on this page
  • Reading pane region, which shows address details for the sender of the current message

Outlook Navigation Pane region: latest mail

This region will show a "sticky" list of all e-mails received since Outlook was launched. It will start out empty, but as new Outlook e-mails are received they will be added to a ListBox. Double-clicking an entry in the ListBox will open the e-mail. Imagine you often spend time in folders other than the Inbox, and need to frequently go back to the Inbox to find an e-mail and open it. Now with this region always displayed no matter what folder you are in, it can be very useful indeed!

Designing the solution

First, we're going to need a region form: launch the Add New Item dialog and select "ADX Region for Outlook and VSTO":

Next, the New Region Wizard will be displayed:

To create a region for the bottom of the Outlook Navigation Pane, select NavigationPane.Bottom in the Explorer Layout dropdown. Then check only MailItem in the Explorer Item Types listbox and click the Next button for the next screen of the Wizard:

The second step of the New Region Wizard is for designing Inspector (or form) Regions. We aren't using this region type in this demonstration, so we'll skip it; click the Next button.

The final screen of the New Region Wizard is where we can set some general properties for the region. Check "Always show header", uncheck "Allow the hidden state" and click the Finish button.

So what just happened? The wizard added a file based on the ADXOlForm class to the project. This is really a Windows Form that serves as a container for the region's custom UI, but it inherits from the AddinExpress.OL.ADXOlForm class instead of System.Windows.Forms.Form. All .NET controls can still be used on this form.

Also behind the scenes, a reference to the AddinExpress.Outlook.Regions.dll assembly was added to the VSTO project. This allows for the implementation of the Add-in Express Regions technology with all of the necessary Objects in the AddinExpress.Extensions and AddinExpress.OL namespaces.

The New Region Wizard also added a very important new component to the project: the FormsManager class:

This class exposes all of the necessary events for interacting with Regions:

  • ADXBeforeFolderSwitchEx
  • ADXBeforeFormInstanceCreate
  • ADXFolderSwitch
  • ADXFolderSwitchEx
  • ADXNavigationPaneHide
  • ADXNavigationPaneMinimize
  • ADXNavigationPaneShow
  • ADXNewInspector
  • ADXReadingPaneHide
  • ADXReadingPaneMove
  • ADXReadingPaneShow
  • ADXTodoBarHide
  • ADXTodoBarMinimize
  • ADXTodoBarShow
  • OnError
  • OnInitialize

Finally, the New Region Wizard added three lines to the project's ThisAddin class to initialize and finalize the regions:

VB.NET

Public Class ThisAddIn 
    Private Sub ThisAddIn_Startup() Handles Me.Startup 
        ' <auto-generated> 
        ' Add-in Express Regions generated code - do not modify 
        Me.FormsManager = AddinExpress.OL.ADXOlFormsManager.CurrentInstance 
        Me.FormsManager.Initialize(Me
        ' </auto-generated> 
    End Sub 
 
    Private Sub ThisAddIn_Shutdown() Handles Me.Shutdown 
        ' <auto-generated> 
        ' Add-in Express Regions generated code - do not modify 
        Me.FormsManager.Finalize(Me
        ' </auto-generated> 
    End Sub 
End Class 

Building the Outlook Navigation Pane region

Although the New Region Wizard automatically added most of the code we need for our new region form into the FormsManager class, we do need to make one small change regarding the caching strategy for the region. By default, new instances of view region forms are created every time the user switches to a folder that matches the context for the region. That is, since we selected MailItem for the Explorer Item types in the New Region Wizard, then the region will be displayed for all Outlook mail folders.

However, the Latest Mail form is intended to remain static for all mail folders as we need to maintain the same list of items no matter which folder is current. To ensure this happens, we need to set the Cached property for the region to ADXOlCachingStrategy.OneInstanceForAllFolders. This way a new instance of the form (with a blank list) is not created when the user navigates to a different mail folder.

VB.NET

Private Sub FormsManager_OnInitialize() Handles FormsManager.OnInitialize 
 
    'ADXOlForm1 
    ' TODO: Use the ADXOlForm3Item properties to configure the region's location, 
    ' appearance and behavior. 
    ' See the "The UI Mechanics" chapter of the Add-in Express Developer's Guide 
    ' for more information. 
    Dim ADXOlForm1Item As ADXOlFormsCollectionItem = New ADXOlFormsCollectionItem() 
    ADXOlForm1Item.ExplorerLayout = ADXOlExplorerLayout.BottomNavigationPane 
    ADXOlForm1Item.ExplorerItemTypes = ADXOlExplorerItemTypes.olMailItem 
    ADXOlForm1Item.AlwaysShowHeader = True 
    ADXOlForm1Item.IsHiddenStateAllowed = False 
    'Must change caching strategy so that the form retains its state for every folder 
    ADXOlForm1Item.Cached = ADXOlCachingStrategy.OneInstanceForAllFolders 
    ADXOlForm1Item.UseOfficeThemeForBackground = True 
    ADXOlForm1Item.FormClassName = GetType(ADXOlForm1).FullName 
    Me.FormsManager.Items.Add(ADXOlForm1Item) 
 
End Sub 

Next, we need to design the UI. Simply add the following controls to ADXOlForm1:

  • Label ("Label1")
  • ListView ("ListView1")
  • ImageList ("ImageList1") - optional if you don't want to use an icon for each item in the list

Then add the following code to the ADXOlForm1 class:

VB.NET

Private Sub ListView1_DoubleClick(ByVal sender As Object, _ 
        ByVal e As System.EventArgs) Handles ListView1.DoubleClick 
 
        Dim myListViewItem As ListViewItem = ListView1.SelectedItems.Item(0) 
        Dim myListViewSubItem As ListViewItem.ListViewSubItem = _ 
            myListViewItem.SubItems.Item(1) 
        Dim myItem As MailItem 
 
        Try 
            myItem = Globals.ThisAddIn.m_OLNameSpace.GetItemFromID(myListViewSubItem.Text) 
        Catch ex As System.Exception 
            'Item may have been deleted or moved: The message you specified cannot be found.  
            MsgBox("The message is no longer available.", _ 
                MessageBoxButtons.OK, "Unknown Error"
            Exit Sub 
        End Try 
 
        If Not myItem Is Nothing Then 
            Try 
                myItem.Display() 
            Catch ex As System.Exception 
                ' Item may have been deleted or moved: The message you specified 
                ' cannot be found. 
                MsgBox("The message is no longer available.", _ 
                    MessageBoxButtons.OK, "Unknown Error"
            End Try 
 
            Marshal.ReleaseComObject(myItem) 
            myItem = Nothing 
        End If 
    End Sub 
 
    Private Sub ADXOlForm1_Load(ByVal sender As Object, _ 
        ByVal e As System.EventArgs) Handles Me.Load 
         
        'The region is loading for the first time in the current Explorer 
        If Globals.ThisAddIn.LatestMessages Is Nothing Then 
            Exit Sub 
        End If 
 
        Dim myListViewItem As System.Windows.Forms.ListViewItem 
 
        'Load an existing list of messages from the property stored in ThisAddIn 
        For Each myListViewItem In Globals.ThisAddIn.LatestMessages 
            Try 
                Dim myNewItem As ListViewItem 
                myNewItem = ListView1.Items.Add(myListViewItem.Clone) 
            Catch ex As System.Exception 
                System.Windows.Forms.MessageBox.Show(ex.ToString) 
            End Try 
 
        Next 
    End Sub 

The code allows for opening the e-mail when a selection in the ListView control is double-clicked, as well as reloading the list of Latest Messages if the user launches a new Explorer window. The list of Latest Messages is actually going to be generated from the ThisAddin class, where we'll demonstrate how to access ADXOlForm1.

Below is the code that will handle incoming e-mails and populating the list on ADXOlForm1. In summary, this is what the code does:

  • Creates Outlook Application and Namespace objects when the add-in loads
  • Implements the Application.NewMailEx event, which will fire every time one e-mail is received
  • Ignore non e-mails (e.g. Meeting requests, etc.)
  • Highlight the region header so that it flashes and catches the user's attention when a new Outlook e-mail is received

VB.NET

Imports System.Runtime.InteropServices 
Imports AddinExpress.OL 
Imports System.Windows.Forms 
 
Public Class ThisAddIn 
    Public m_OLNameSpace As Outlook.NameSpace 
    Private WithEvents m_OutlookApp As Outlook.Application 
    Private m_LatestMailRegion As ADXOlFormsCollectionItem 
    Public Property LatestMessages() As ListView.ListViewItemCollection 
 
    Private Sub ThisAddIn_Startup() Handles Me.Startup 
 
        ' <auto-generated> 
        ' Add-in Express Regions generated code - do not modify 
        Me.FormsManager = AddinExpress.OL.ADXOlFormsManager.CurrentInstance 
        Me.FormsManager.Initialize(Me
        ' </auto-generated> 
 
        m_OutlookApp = Me.Application 
        m_OLNameSpace = Me.Application.GetNamespace("MAPI"
    End Sub 
 
    Private Sub ThisAddIn_Shutdown() Handles Me.Shutdown 
 
        ' <auto-generated> 
        ' Add-in Express Regions generated code - do not modify 
        Me.FormsManager.Finalize(Me
        ' </auto-generated> 
 
        Marshal.ReleaseComObject(m_OLNameSpace) 
    End Sub 
 
    Private Sub m_OutlookApp_NewMailEx(ByVal EntryIDCollection As String) _ 
        Handles m_OutlookApp.NewMailEx 
         
        Dim objExplorers As Outlook.Explorers 
 
        Try 
            objExplorers = Application.Explorers 
            If Not objExplorers Is Nothing Then 
                If objExplorers.Count = 0 Then 
                    GoTo Leave 
                End If 
            Else 
                Exit Sub 
            End If 
        Catch ex As System.Exception 
            System.Windows.Forms.MessageBox.Show(ex.ToString) 
            Exit Sub 
        End Try 
 
        Dim objNewItem As Object 
        Dim strEntryIDs() As String 
 
        'Get the list of EntryIDs passed to NewMailEx 
        'NOTE: NewMailEx in Outlook 2007/2010 only processes ONE new message in this event. 
        'For backwards compatibility with Outlook 2003, this code will loop through 
        'all EntryIDs 
        strEntryIDs = Split(EntryIDCollection, ","
 
        For Each strID As String In strEntryIDs 
            Try 
                'Get an item Object for each EntryID in the collection 
                objNewItem = m_OLNameSpace.GetItemFromID(strID) 
                If Not objNewItem Is Nothing Then 
                    'Only handle e-mails 
                    If objNewItem.Class = Outlook.OlObjectClass.olMail Then 
                        Dim objMail As Outlook.MailItem = _ 
                            TryCast(objNewItem, Outlook.MailItem)                         
 
                        'Loop through all Explorers and add latest message to ListView 
                        'control on every region 
                        For intX As Integer = 1 To objExplorers.Count 
                            Dim objExpl As Outlook.Explorer = objExplorers.Item(intX) 
                            Dim myADXOlForm1 As ADXOlForm1 = Nothing 
                            Dim myADOlRegionForm As AddinExpress.OL.ADXOlForm 
                            Dim objExplrHWND As IntPtr 
 
                            objExplrHWND = FormsManager.GetOutlookWindowHandle(objExpl) 
 
                            'Get the active Region instance 
                            myADOlRegionForm = FindForm(objExplrHWND) 
 
                            If Not myADOlRegionForm Is Nothing Then 
                                'Convert the ADXOlForm form to our instance of it 
                                myADXOlForm1 = TryCast(myADOlRegionForm, ADXOlForm1) 
 
                                If Not myADXOlForm1 Is Nothing Then 
                                    Dim myListViewItem As System.Windows.Forms.ListViewItem 
                                    Dim myListViewSubItem As _ 
                                        Windows.Forms.ListViewItem.ListViewSubItem 
 
                                    'Add the message's Subject to the ListView control 
                                    myListViewItem = _ 
                                        myADXOlForm1.ListView1.Items.Add(objMail.Subject) 
                                    myListViewItem.ToolTipText = objMail.Subject 
                                    'Optional if an ImageList control is not being used 
                                    myListViewItem.ImageKey = "Mail.ico" 
 
                                    myListViewSubItem = myListViewItem.SubItems.Add(strID) 
                                    'Store the last accessed list of items in a Public 
                                    'property for retrieval when creating the region 
                                    'in a new Explorer window (so the ListView can be 
                                    'repopulated) 
                                    LatestMessages = myADXOlForm1.ListView1.Items 
 
                                    'Highlight the region to notify the user that new 
                                    'mail has been received 
                                    myADXOlForm1.Highlight() 
                                End If 
                            End If 
                            objExpl = Nothing 
                        Next 
 
                        Marshal.ReleaseComObject(objNewItem) 
                        objNewItem = Nothing 
                        objMail = Nothing 
                    End If 
                End If 
            Catch ex As System.Exception 
                System.Windows.Forms.MessageBox.Show(ex.ToString) 
            End Try 
        Next 
 
Leave: 
        Marshal.ReleaseComObject(objExplorers) 
        objExplorers = Nothing 
    End Sub 
 
    Public Property LatestMailRegion As ADXOlFormsCollectionItem 
        Get 
            Return FormsManager.Items(0) 
        End Get 
        Set(ByVal value As ADXOlFormsCollectionItem) 
            m_LatestMailRegion = value 
        End Set 
    End Property 
 
    Public Function FindForm(ByVal CurrentOutlookWindowHandle As IntPtr) _ 
        As AddinExpress.OL.ADXOlForm 
 
        For i As Integer = 0 To LatestMailRegion.FormInstanceCount - 1 
            If LatestMailRegion.FormInstances(i).Visible AndAlso _ 
                CurrentOutlookWindowHandle = _ 
                LatestMailRegion.FormInstances(i).CurrentOutlookWindowHandle Then 
                Return TryCast(LatestMailRegion.FormInstances(i), AddinExpress.OL.ADXOlForm) 
            End If 
        Next 
 
        Return Nothing 
    End Function 
End Class