Visual Studio 2008 Beta 2 is available today and with it, a new age of Office development begins. Visual Studio Professional 2008 now includes all the Office projects previously only in the Visual Studio Tools for Office or Visual Studio Team System products. So now everyone can build extensions for Office.
Now that the Office projects are available throughout the Visual Studio offerings, a new set of developers will be approaching Office development for the first time. For that audience and for new comers to the new Office features in Visual Studio 2008, I want to highlight how easy it is to create extensions for Outlook. Much has been written about the new Outlook development features in VS 2008, but what I want to show you is a basic design pattern that can be reused for many different kinds of Outlook solutions. This design pattern involves creating a custom Outlook Message Class and associating something called a Forms Region with it.
In my example, I'm going to create a little add-in that I'm calling "WebView". My WebView add-in will let you take any Outlook mail item and let you view it in the reading pane with internet explorer instead of Outlook's built in preview engine. Some mail messages that are composed in HTML display better in IE than in Outlook--for example, in my world our rolling build machines sends e-mail about the status of our Visual Studio build in HTML and the indentation of the build status mail doesn't render well in Outlook's built in engine. So I'm going to extend Outlook so I can mark particular mail items to display with IE in the reading pane.
The way I do this is by defining a custom message class in Outlook that derives from the message class for mail items and associate that custom message class with a Forms Region. Now we're not talking classes in the sense of a code class, but instead message classes are strings that tell Outlook how to render a particular item. Mail items in Outlook are assigned the string "IPM.Note". I am going to define a new message class by assigning it the string "IPM.Note.WebView". Outlook knows that this is derived from the basic mail item message class because it contains the substring "IPM.Note" in the new message class definition. So Outlook will continue to associate with my derived mail item all the basic mail functionality in IPM.Note. But given this new message class, I can replace some of Outlook's built in behavior--in particular I can associate a Forms Region with the new message class. This Forms Region is a Windows Form that replaces Outlook's built in view for the item.
To do this with Visual Studio 2008 Beta 2, start by creating a new Outlook 2007 add-in as the Forms Region feature only works with Outlook 2007 and later. Below you can see the various Office 2007 projects that are available in Visual Studio 2008. There are also a number of Office 2003 projects available as well.
I'm going to name my add-in "WebView". Next, I am going to create a Forms Region. To do this, I right click on the project and choose "Add > New Item..." I then get the dialog below which lets me choose to add a forms region.
I will call my form region WebView. Next, I go through a wizard to configure my form region. The first page prompts me to either design a new form region from scratch using Windows Forms controls or to import an existing OFS file that contains Outlook native controls. For this example, I am going to use Windows Forms.
Next, I choose amongst the different types of available form regions. In this case I am going to choose Replacement to replace the default view for my new message class (e.g. replace the default mail view associated with the IPM.Note class).
Because I'm doing a replacement, I am forced to create a new message class which is what I want to do here anyway. The "Separate" and "Adjoining" form regions types let you extend an existing message class without creating a new message class. But to fully replace the default view and get the look I want, I'm creating a new message class in this design pattern. Note I type my new message class in the bottom field: "IPM.Note.WebView"
Finally, the wizard prompts me for the name of the form region, a description, and whether I want to display the form region in all modes. I only want to display my form region in read and reading pane mode--in compose mode I just want the default Outlook editor for mail.
Once the wizard is completed, I get a visual designer that looks just like the Windows Forms User Control designer where I can design the forms region that I want to have displayed for my new message class. I drag a WebBrowser control onto my form region designer for "WebView.vb".
Then, I'm going to add some code behind this form region. I am gong to edit the WebView.vb code to add the following to the existing "FormRegionShowing" method. The code I add is in bold. This code grabs the Outlook mail item associated with the form region (Me.OutlookItem) and casts it from an Object to an Outlook.MailItem. Then it sets the WebBrowser control's DocumentText property to the HTMLBody property of the mail item--this property returns the HTML for the mail item:
Private Sub WebView_FormRegionShowing(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.FormRegionShowing Dim m As Outlook.MailItem m = CType(Me.OutlookItem, Outlook.MailItem) Me.WebBrowser1.DocumentText = m.HTMLBodyEnd Sub
Now my form region is complete--any time a mail item is clicked on with the message class "IPM.Note.WebView" it will display my form region as a replacement view and that form region will show the mail item in IE using the HTML of the mail item.
The next step is to provide some code to allow the user to convert a mail item from type "IPM.Note" to type "IPM.Note.WebView" which will trigger the IE based view of the mail item when the message class changes. The code to do this is written in the built-in "ThisAddin.vb" class that appears in an Outlook add-in project. Basically, I add a command bar button to the context menu that appears when you right click on an outlook add-in. I add this command bar button by handling the ItemContextMenuDisplay event on the application object. I set whether the button (which will have the caption "Show using WebView") is checked or not depending on whether the message class is already set to IPM.Note.WebView (checked) or it is set to IPM.Note (uncheck).
When the user selects my command bar button in the context menu, I toggle the message class between IPM.Note.WebView and IPM.Note. I then "refresh" the reading view by forcing a hide then show of it to make sure the reading view shows my IE view of the mail item.
Public Class ThisAddIn
Public WithEvents ChangeToWebViewButton As Office.CommandBarButton Public Selection As Outlook.Selection
Private Sub ThisAddIn_Startup(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Startup
Private Sub ThisAddIn_Shutdown(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Shutdown
Private Sub Application_ItemContextMenuDisplay(ByVal CommandBar As Microsoft.Office.Core.CommandBar, ByVal Selection As Microsoft.Office.Interop.Outlook.Selection) Handles Application.ItemContextMenuDisplay
ChangeToWebViewButton = CommandBar.Controls.Add(Office.MsoControlType.msoControlButton, , , , True) ChangeToWebViewButton.Caption = "Show using WebView"
If (Selection.Count > 0) Then Dim o As Object = Selection(1) If Not IsNothing(o) Then Dim messageClass As String = o.MessageClass
If messageClass = "IPM.Note.WebView" Then ChangeToWebViewButton.State = Microsoft.Office.Core.MsoButtonState.msoButtonDown Else ChangeToWebViewButton.State = Microsoft.Office.Core.MsoButtonState.msoButtonUp End If End If End If
Me.Selection = Selection End Sub
Private Sub ChangeToWebViewButton_Click(ByVal Ctrl As Microsoft.Office.Core.CommandBarButton, ByRef CancelDefault As Boolean) Handles ChangeToWebViewButton.Click Dim o As Object
For Each o In Selection Dim mailItem As Outlook.MailItem
Try mailItem = CType(o, Outlook.MailItem) Catch ex As Exception Continue For End Try
TogglePreviewPane() ChangeToWebViewButton = Nothing Selection = Nothing End Sub
Public Shared Sub ToggleMessageClass(ByVal mailItem As Outlook.MailItem) If Not IsNothing(mailItem) Then If mailItem.MessageClass = "IPM.Note.WebView" Then mailItem.MessageClass = "IPM.Note" Else mailItem.MessageClass = "IPM.Note.WebView" End If End If mailItem.Save() End Sub
Public Sub TogglePreviewPane() Dim explorer As Outlook.Explorer explorer = Application.ActiveExplorer() If explorer.IsPaneVisible(Outlook.OlPane.olPreview) Then explorer.ShowPane(Outlook.OlPane.olPreview, False) explorer.ShowPane(Outlook.OlPane.olPreview, True) End If End Sub
The result of all this is the following--now when I get my build mail that has improper indentation because of Outlook 2007's rendered, I can right click on the mail to see my "Show using WebView" command bar button. Note that it isn't checked because the message class of this item is currently IPM.Note:
When I select "Show using WebView" the message class of the item is changed to IPM.Note.WebView. The reading view is refreshed. Outlook realizes it is a custom message class and that a form region is registered for it. It then loads the form region which is just my windows form with the internet browser control on it. My form region code grabs the HTMLBody of the mail message and feeds it to the internet browser control and voila!:
Now you'll note that my form region *really* takes over the entire view including the area that Outlook uses to show who the message is from, etc. So to complete this solution, I would have to enhance my form region to show that information above the web browser control with some other controls on the form region or by adding additional HTML to be displayed by the web browser control in addition to the HTMLBody of the message. I leave that as an exercise for the reader :)
Also, when you double click on the mail item that now has the "IPM.Note.WebView" message class, my forms region also appears in the stand-alone window for the mail item (aka an Inspector in Read Mode):
With some imagination, you can see how this basic design pattern can apply to a wide range of solutions where you can build your own custom renderer for your own custom message class type. Another idea for enhancement: I could enhance my server script that sends my build mail to send a mail of the custom message type so that the user doesn't even have to choose to change to web view--it would just display a web view by default.
Hopefully this will spark some ideas for building your own add-ins with Visual Studio 2008 Beta 2. And yes--I did this whole article with the actual beta, so you should be able to try this at home :)