How to: Display Custom Task Panes with E-Mail Messages in Outlook

The following code displays a unique custom task pane in the Inspector window of every e-mail message that is opened. For more information, including instructions for using the code examples in this topic, see Walkthrough: Displaying Custom Task Panes with E-Mail Messages in Outlook.

The following code examples provide the complete contents of the following add-in project files:

  • The Ribbon.xml file.

  • The Ribbon.cs or Ribbon.vb file.

  • The ThisAddIn.cs or ThisAddIn.vb file.

Examples

Ribbon XML file

  • Replace the contents of the Ribbon.xml file in your add-in with the following XML.

    <customUI xmlns="https://schemas.microsoft.com/office/2006/01/customui" onLoad="OnLoad">
      <ribbon>
        <tabs>
          <tab idMso="TabAddIns">
            <group id="MyGroup"
                   label="Task Pane">
              <toggleButton id="toggleTaskPane"
                            size="large"
                            label="Show/Hide Task Pane"
                            screentip="Show/Hide Task Pane"
                            onAction="OnToggleTaskPane"
                            getPressed="GetPressedState"
                            imageMso="HappyFace" />
            </group>
          </tab>
        </tabs>
      </ribbon>
    </customUI>
    

Ribbon code file

  • Replace the contents of the Ribbon.cs or Ribbon.vb file in your add-in with the following code.

    Imports System
    Imports System.Collections.Generic
    Imports System.Diagnostics
    Imports System.IO
    Imports System.Text
    Imports System.Reflection
    Imports System.Runtime.InteropServices
    Imports System.Windows.Forms
    Imports Office = Microsoft.Office.Core
    Imports Outlook = Microsoft.Office.Interop.Outlook
    Imports Microsoft.Office.Tools
    
    Partial Public Class ThisAddIn
    
        Public ribbon As Ribbon
    
        Protected Overrides Function RequestService(ByVal serviceGuid As Guid) As Object
            If serviceGuid = GetType(Office.IRibbonExtensibility).GUID Then
                If ribbon Is Nothing Then
                    ribbon = New Ribbon()
                End If
                Return ribbon
            End If
    
            Return MyBase.RequestService(serviceGuid)
        End Function
    
    End Class
    
    <ComVisible(True)> _
        Public Class Ribbon
        Implements Office.IRibbonExtensibility
    
        Private ribbon As Office.IRibbonUI
    
        Public Sub New()
        End Sub
    
    #Region "IRibbonExtensibility Members"
    
        Public Function GetCustomUI(ByVal ribbonID As String) As String Implements Office.IRibbonExtensibility.GetCustomUI
            Select Case ribbonID
                Case "Microsoft.Outlook.Mail.Read", "Microsoft.Outlook.Mail.Compose"
                    Return GetResourceText("OutlookMailItemTaskPane.Ribbon.xml")
                Case Else
                    Return String.Empty
            End Select
        End Function
    #End Region
    
    #Region "Ribbon Callbacks"
    
        Public Sub OnLoad(ByVal ribbonUI As Office.IRibbonUI)
            Me.ribbon = ribbonUI
        End Sub
    
        Public Sub OnToggleTaskPane(ByVal control As Office.IRibbonControl, ByVal isPressed As Boolean)
            Dim inspector As Outlook.Inspector = control.Context
            Dim inspectorWrapper As InspectorWrapper = Globals.ThisAddIn.inspectorWrappers(inspector)
            Dim taskPane As CustomTaskPane = inspectorWrapper.CustomTaskPane
            If Not (taskPane Is Nothing) Then
                taskPane.Visible = isPressed
            End If
        End Sub
    
        Public Function GetPressedState(ByVal control As Office.IRibbonControl) As Boolean
            Dim inspector As Outlook.Inspector = control.Context
            If Globals.ThisAddIn.inspectorWrappers.ContainsKey(inspector) Then
                Dim inspectorWrapper As InspectorWrapper = Globals.ThisAddIn.inspectorWrappers(inspector)
                Dim taskPane As CustomTaskPane = inspectorWrapper.CustomTaskPane
    
                If taskPane IsNot Nothing Then
                    Return taskPane.Visible
                Else
                    Return False
                End If
            Else
                Return False
            End If
        End Function
    
    #End Region
    
        Public Sub RefreshControl(ByVal controlID As String)
            ribbon.InvalidateControl(controlID)
        End Sub
    
        Public ReadOnly Property RibbonUI() As Office.IRibbonUI
            Get
                Return ribbon
            End Get
        End Property
    
    #Region "Helpers"
    
        Private Shared Function GetResourceText(ByVal resourceName As String) As String
            Dim asm As Assembly = Assembly.GetExecutingAssembly()
            Dim resourceNames() As String = asm.GetManifestResourceNames()
            For i As Integer = 0 To resourceNames.Length - 1
                If String.Compare(resourceName, resourceNames(i), StringComparison.OrdinalIgnoreCase) = 0 Then
                    Using resourceReader As StreamReader = New StreamReader(asm.GetManifestResourceStream(resourceNames(i)))
                        If resourceReader IsNot Nothing Then
                            Return resourceReader.ReadToEnd()
                        End If
                    End Using
                End If
            Next
            Return Nothing
        End Function
    
    #End Region
    
    End Class
    
    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.IO;
    using System.Text;
    using System.Reflection;
    using System.Runtime.InteropServices;
    using System.Windows.Forms;
    using Office = Microsoft.Office.Core;
    using Outlook = Microsoft.Office.Interop.Outlook;
    using Microsoft.Office.Tools;
    
    namespace OutlookMailItemTaskPane
    {
        public partial class ThisAddIn
        {
            public Ribbon ribbon;
    
            protected override object RequestService(Guid serviceGuid)
            {
                if (serviceGuid == typeof(Office.IRibbonExtensibility).GUID)
                {
                    if (ribbon == null)
                        ribbon = new Ribbon();
                    return ribbon;
                }
    
                return base.RequestService(serviceGuid);
            }
        }
    
        [ComVisible(true)]
        public class Ribbon : Office.IRibbonExtensibility
        {
            private Office.IRibbonUI ribbon;
    
            public Ribbon()
            {
            }
    
            #region IRibbonExtensibility Members
    
            public string GetCustomUI(string ribbonID)
            {
                switch (ribbonID)
                {
                    case "Microsoft.Outlook.Mail.Read":
                    case "Microsoft.Outlook.Mail.Compose":
                        return GetResourceText("OutlookMailItemTaskPane.Ribbon.xml");
                    default:
                        return String.Empty;
                }
            }
    
            #endregion
    
            #region Ribbon Callbacks
    
            public void OnLoad(Office.IRibbonUI ribbonUI)
            {
                this.ribbon = ribbonUI;
            }
    
            public void OnToggleTaskPane(Office.IRibbonControl control, bool isPressed)
            {
                Outlook.Inspector inspector = (Outlook.Inspector)control.Context;
                InspectorWrapper inspectorWrapper = Globals.ThisAddIn.inspectorWrappers[inspector];
                CustomTaskPane taskPane = inspectorWrapper.CustomTaskPane;
                if (taskPane != null)
                {
                    taskPane.Visible = isPressed;
                }
            }
    
            public bool GetPressedState(Office.IRibbonControl control)
            {
                Outlook.Inspector inspector = (Outlook.Inspector)control.Context;
                if (Globals.ThisAddIn.inspectorWrappers.ContainsKey(inspector))
                {
                    InspectorWrapper inspectorWrapper = Globals.ThisAddIn.inspectorWrappers[inspector];
                    CustomTaskPane taskPane = inspectorWrapper.CustomTaskPane;
    
                    if (null != taskPane)
                    {
                        return taskPane.Visible;
                    }
                    else
                    {
                        return false;
                    }
                }
                else
                {
                    return false;
                }
            }
    
            #endregion
    
            public void RefreshControl(string controlID)
            {
                ribbon.InvalidateControl(controlID);
            }
    
            public Office.IRibbonUI RibbonUI
            {
                get 
                { 
                    return ribbon; 
                }
            }
    
            #region Helpers
    
            private static string GetResourceText(string resourceName)
            {
                Assembly asm = Assembly.GetExecutingAssembly();
                string[] resourceNames = asm.GetManifestResourceNames();
                for (int i = 0; i < resourceNames.Length; ++i)
                {
                    if (string.Compare(resourceName, resourceNames[i], StringComparison.OrdinalIgnoreCase) == 0)
                    {
                        using (StreamReader resourceReader = new StreamReader(asm.GetManifestResourceStream(resourceNames[i])))
                        {
                            if (resourceReader != null)
                            {
                                return resourceReader.ReadToEnd();
                            }
                        }
                    }
                }
                return null;
            }
    
            #endregion
        }
    }
    

ThisAddIn code file

  • Replace the contents of the ThisAddIn.cs or ThisAddIn.vb file in your add-in with the following code.

    Imports System.Collections.Generic
    Imports Microsoft.Office.Tools
    
    Public Class InspectorWrapper
        Private WithEvents inspector As Outlook.Inspector
        Private WithEvents taskPane As CustomTaskPane
    
        Public Sub New(ByVal Inspector As Outlook.Inspector)
            Inspector = Inspector
            taskPane = Globals.ThisAddIn.CustomTaskPanes.Add(New TaskPaneControl(), "My task pane", Inspector)
            taskPane.Visible = True
        End Sub
    
        Sub TaskPane_VisibleChanged(ByVal sender As Object, ByVal e As EventArgs) Handles taskPane.VisibleChanged
            Globals.ThisAddIn.ribbon.RefreshControl("toggleTaskPane")
        End Sub
    
        Sub InspectorWrapper_Close() Handles inspector.Close
            If Not (taskPane Is Nothing) Then
                Globals.ThisAddIn.CustomTaskPanes.Remove(taskPane)
            End If
    
            taskPane = Nothing
            Globals.ThisAddIn.inspectorWrappers.Remove(inspector)
            RemoveHandler inspector.Close, AddressOf InspectorWrapper_Close
            inspector = Nothing
        End Sub
    
        Public ReadOnly Property CustomTaskPane() As CustomTaskPane
            Get
                Return taskPane
            End Get
        End Property
    End Class
    
    public class ThisAddIn
    
        Public inspectorWrappers As New Dictionary(Of Outlook.Inspector, InspectorWrapper)
        Private WithEvents inspectors As Outlook.Inspectors
    
        Private Sub ThisAddIn_Startup(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Startup
            inspectors = Me.Application.Inspectors
    
            Dim inspector As Outlook.Inspector
            For Each inspector In inspectors
                Inspectors_NewInspector(inspector)
            Next inspector
        End Sub
    
        Private Sub ThisAddIn_Shutdown(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Shutdown
            RemoveHandler inspectors.NewInspector, AddressOf Inspectors_NewInspector
            inspectors = Nothing
            inspectorWrappers = Nothing
        End Sub
    
        Sub Inspectors_NewInspector(ByVal Inspector As Outlook.Inspector) _
            Handles inspectors.NewInspector
    
            If TypeOf Inspector.CurrentItem Is Outlook.MailItem Then
                inspectorWrappers.Add(Inspector, New InspectorWrapper(Inspector))
    
                If ribbon IsNot Nothing AndAlso ribbon.RibbonUI IsNot Nothing Then
                    ribbon.RefreshControl("toggleTaskPane")
                End If
            End If
        End Sub
    End class
    
    using System;
    using System.Windows.Forms;
    using Microsoft.VisualStudio.Tools.Applications.Runtime;
    using Outlook = Microsoft.Office.Interop.Outlook;
    using Office = Microsoft.Office.Core;
    using System.Collections.Generic;
    using Microsoft.Office.Tools;
    
    namespace OutlookMailItemTaskPane
    {
        public class InspectorWrapper
        {
            Outlook.Inspector inspector;
            CustomTaskPane taskPane;
    
            public InspectorWrapper(Outlook.Inspector Inspector)
            {
                inspector = Inspector;
                ((Outlook.InspectorEvents_Event)inspector).Close +=
                    new Outlook.InspectorEvents_CloseEventHandler(InspectorWrapper_Close);
    
                taskPane = Globals.ThisAddIn.CustomTaskPanes.Add(
                    new TaskPaneControl(), "My task pane", inspector);
                taskPane.Visible = true;
                taskPane.VisibleChanged += new EventHandler(TaskPane_VisibleChanged);
            }
    
            void TaskPane_VisibleChanged(object sender, EventArgs e)
            {
                Globals.ThisAddIn.ribbon.RefreshControl("toggleTaskPane");
            }
    
            void InspectorWrapper_Close()
            {
                if (taskPane != null)
                {
                    Globals.ThisAddIn.CustomTaskPanes.Remove(taskPane);
                }
    
                taskPane = null;
                Globals.ThisAddIn.inspectorWrappers.Remove(inspector);
                ((Outlook.InspectorEvents_Event)inspector).Close -=
                    new Outlook.InspectorEvents_CloseEventHandler(InspectorWrapper_Close);
                inspector = null;
            }
    
            public CustomTaskPane CustomTaskPane
            {
                get 
                {
                    return taskPane;
                }
            }
        }
    
        public partial class ThisAddIn
        {
            public Dictionary<Outlook.Inspector, InspectorWrapper> inspectorWrappers =
                new Dictionary<Outlook.Inspector, InspectorWrapper>();
            private Outlook.Inspectors inspectors;
    
            private void ThisAddIn_Startup(object sender, System.EventArgs e)
            {
                inspectors = this.Application.Inspectors;
                inspectors.NewInspector +=
                    new Outlook.InspectorsEvents_NewInspectorEventHandler(Inspectors_NewInspector);
    
                foreach (Outlook.Inspector inspector in inspectors)
                {
                    Inspectors_NewInspector(inspector);
                }
            }
    
            private void ThisAddIn_Shutdown(object sender, System.EventArgs e)
            {
                inspectors.NewInspector -=
                    new Outlook.InspectorsEvents_NewInspectorEventHandler(Inspectors_NewInspector);
                inspectors = null;
                inspectorWrappers = null;
            }
    
            void Inspectors_NewInspector(Outlook.Inspector Inspector)
            {
                if (Inspector.CurrentItem is Outlook.MailItem)
                {
                    inspectorWrappers.Add(Inspector, new InspectorWrapper(Inspector));
    
                    if (null != ribbon && null != ribbon.RibbonUI)
                    {
                        ribbon.RefreshControl("toggleTaskPane");
                    }
                }
            }
    
            #region VSTO generated code
    
            /// <summary>
            /// Required method for Designer support - do not modify
            /// the contents of this method with the code editor.
            /// </summary>
            private void InternalStartup()
            {
                this.Startup += new System.EventHandler(ThisAddIn_Startup);
                this.Shutdown += new System.EventHandler(ThisAddIn_Shutdown);
            }
    
            #endregion
        }
    }
    

See Also

Tasks

Walkthrough: Displaying Custom Task Panes with E-Mail Messages in Outlook
How to: Add a Custom Task Pane to an Application
How to: Customize the Ribbon

Concepts

Custom Task Panes Overview
Ribbon Extensibility Overview
Outlook Object Model Overview