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.
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>
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 } }
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 } }
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
Custom Task Panes Overview
Ribbon Extensibility Overview
Outlook Object Model Overview