Outlook has many events that occur at the Outlook item level. We refer to Item events in this section, but there is no Item object per se in the Outlook object model. Instead, you will find Item events on each of the 15 Outlook object model objects listed in Table 10-1.
Item Addition, Deletion, and Change Events
Several events are raised when Outlook items are added, deleted, or changed:
Listing 10-5 shows some VSTO Outlook add-in code that handles these events. To get to an individual MailItem to handle the Item.BeforeDelete event, the code first gets the NameSpace object. The NameSpace object is accessed by calling the Application.Session property. The NameSpace object has a method called GetDefaultFolder that returns a MAPIFolder to which you can pass a member of the enumeration OlDefaultFolders to get a standard Outlook folder. In Listing 10-5, we pass olFolderInbox to get a MAPIFolder for the Inbox. We then use the Items collection associated with the Inbox's MAPIFolder to connect our event handlers to as well as to get an individual MailItem to handle the Item.BeforeDelete event for.
Listing 10-5. A VSTO Add-In That Handles Item Addition, Change, and Delete Events
namespace OutlookAddin1 { public partial class ThisApplication { Outlook.MailItem mailItem; Outlook.Items items; private void ThisApplication_Startup(object sender, EventArgs e) { Outlook.NameSpace ns = this.Session; Outlook.MAPIFolder inbox = ns. GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox); foreach (object o in inbox.Items) { mailItem = o as Outlook.MailItem; if (mailItem != null) { break; } } if (mailItem == null) { MessageBox.Show("Couldn't find a mail item to connect to."); } else { mailItem.BeforeDelete += new Outlook.ItemEvents_10_BeforeDeleteEventHandler( MailItem_BeforeDelete); MessageBox.Show(String.Format( "Connected to the mail item with subject {0}.", mailItem.Subject)); } items = inbox.Items; items.ItemRemove += new Outlook.ItemsEvents_ItemRemoveEventHandler( Items_ItemRemove); items.ItemChange += new Outlook.ItemsEvents_ItemChangeEventHandler( Items_ItemChange); items.ItemAdd += new Outlook.ItemsEvents_ItemAddEventHandler( Items_ItemAdd); } void MailItem_BeforeDelete(object item, ref bool cancel) { MessageBox.Show(String.Format( "The mail item {0} cannot be deleted.", mailItem.Subject)); cancel = true; } void Items_ItemRemove() { MessageBox.Show("An item is about to be removed."); } void GenerateItemMessage(object item, string operation) { Outlook.MailItem mailItem = item as Outlook.MailItem; if (mailItem != null) { MessageBox.Show(String.Format( "MailItem {0} was just {1}.", mailItem.Subject, operation)); } else { MessageBox.Show(String.Format( "An Outlook item was just {0}.", operation)); } } void Items_ItemChange(object item) { GenerateItemMessage(item, "changed"); } void Items_ItemAdd(object item) { GenerateItemMessage(item, "added"); } } }
Copy, Paste, Cut, and Delete Events
Outlook raises several events when Outlook items are copied, cut, or pasted. These events are raised on an Explorer object. An Explorer object has a Selection property that returns the current selected items in the Explorer. Because many of the Explorer events telling you that a copy, cut, or paste is about to occur do not pass the items that are being acted upon, you must examine the Selection object to determine the items that are being acted upon:
Listing 10-6 shows a VSTO Outlook add-in that handles these events. It uses a helper function called GenerateItemsMessage that iterates over the items in a Selection object and displays a dialog with the subject of each MailItem selected.
Listing 10-6. A VSTO Add-In That Handles Copy, Cut, and Paste Events
namespace OutlookAddin1 { public partial class ThisApplication { Outlook.Explorer explorer; private void ThisApplication_Startup(object sender, EventArgs e) { explorer = this.ActiveExplorer(); explorer.BeforeItemCopy += new Outlook.ExplorerEvents_10_BeforeItemCopyEventHandler( Explorer_BeforeItemCopy); explorer.BeforeItemCut += new Outlook.ExplorerEvents_10_BeforeItemCutEventHandler( Explorer_BeforeItemCut); explorer.BeforeItemPaste += new Outlook.ExplorerEvents_10_BeforeItemPasteEventHandler( Explorer_BeforeItemPaste); } void GenerateItemsMessage(Outlook.Selection selection, string operation) { System.Text.StringBuilder b = new System.Text.StringBuilder(); b.AppendFormat("Items to be {0}: ", operation); foreach (object o in selection) { Outlook.MailItem mi = o as Outlook.MailItem; if (mi != null) { b.AppendFormat("MailItem: {0} ", mi.Subject); } else { b.AppendLine("Other Outlook item"); } } MessageBox.Show(b.ToString()); } void Explorer_BeforeItemCopy(ref bool cancel) { GenerateItemsMessage(explorer.Selection, "copied"); } void Explorer_BeforeItemCut(ref bool cancel) { GenerateItemsMessage(explorer.Selection, "cut"); } void Explorer_BeforeItemPaste(ref object clipboardContent, Outlook.MAPIFolder target, ref bool cancel) { if (clipboardContent is Outlook.Selection) { Outlook.Selection selection = clipboardContent as Outlook.Selection; GenerateItemsMessage(selection, "pasted"); } else { MessageBox.Show("The clipboard is not a Selection object."); } } } }
Property Change Events
A typical Outlook item has many associated properties, such as CreationTime, Importance, LastModificationTime, and so on. All the properties associated with an Outlook item are contained by the ItemProperties property. When any of these properties are changed, Outlook raises the PropertyChange event. It is also possible to define additional custom properties and associate them with an Outlook item. When custom properties are changed, Outlook raises the CustomPropertyChange event:
Open, Read, Write, and Close Events
Outlook raises events when an Outlook item is opened, written to, or closed:
Close is the name of both a method and an event on Outlook item objects. Because of this collision, you will not see the Close event in Visual Studio's pop-up menu of properties, events, and methods associated with an Outlook item. Furthermore, a warning displays at compile time when you try to handle this event. To get Visual Studio's pop-up menus to work and the warning to go away, you can cast the Explorer object to the ItemEvents_10_Event, as shown in Listing 10-7. |
Listing 10-7 shows a VSTO Outlook add-in that handles these events.
Listing 10-7. A VSTO Add-In That Handles Open, Read, Write, and Close Events
namespace OutlookAddin1 { public partial class ThisApplication { Outlook.MailItem mailItem; private void ThisApplication_Startup(object sender, EventArgs e) { Outlook.NameSpace ns = this.Session; Outlook.MAPIFolder inbox = ns.GetDefaultFolder( Outlook.OlDefaultFolders.olFolderInbox); foreach (object o in inbox.Items) { mailItem = o as Outlook.MailItem; if (mailItem != null) { break; } } if (mailItem == null) { MessageBox.Show("Couldn't find a mail item to connect to."); } else { MessageBox.Show(String.Format( "Connected to the mail item with subject {0}.", mailItem.Subject); mailItem.Read += new Outlook.ItemEvents_10_ReadEventHandler( MailItem_Read); mailItem.Open += new Outlook.ItemEvents_10_OpenEventHandler( MailItem_Open); mailItem.Write += new Outlook.ItemEvents_10_WriteEventHandler( MailItem_Write); ((Outlook.ItemEvents_10_Event)mailItem).Close += new Outlook.ItemEvents_10_CloseEventHandler( MailItem_Close); } } void MailItem_Read() { MessageBox.Show("Read"); } void MailItem_Open(ref bool cancel) { MessageBox.Show("Open"); } void MailItem_Write(ref bool cancel) { MessageBox.Show("Write"); } void MailItem_Close(ref bool cancel) { MessageBox.Show("Close"); } } }
E-mail Events
Outlook raises several e-mail-related events when new mail is received, when an Outlook item is sent by e-mail, or when an Outlook item is forwarded or replied to:
Listing 10-8 shows a VSTO Outlook add-in that handles these events.
Listing 10-8. A VSTO Add-In That Handles E-mail Events
namespace OutlookAddin1 { public partial class ThisApplication { Outlook.MailItem mailItem; private void ThisApplication_Startup(object sender, EventArgs e) { this.NewMail += new Outlook.ApplicationEvents_11_NewMailEventHandler( ThisApplication_NewMail); this.NewMailEx += new Outlook.ApplicationEvents_11_NewMailExEventHandler( ThisApplication_NewMailEx); this.ItemSend += new Outlook.ApplicationEvents_11_ItemSendEventHandler( ThisApplication_ItemSend); Outlook.NameSpace ns = this.Session; Outlook.MAPIFolder inbox = ns.GetDefaultFolder( Outlook.OlDefaultFolders.olFolderInbox); foreach (object o in inbox.Items) { mailItem = o as Outlook.MailItem; if (mailItem != null) { break; } } if (mailItem == null) { MessageBox.Show("Couldn't find a mail item."); } else { MessageBox.Show(String.Format( "Connected to the mail item {0}.", mailItem.Subject)); ((Outlook.ItemEvents_10_Event)mailItem).Send += new Outlook.ItemEvents_10_SendEventHandler( MailItem_Send); ((Outlook.ItemEvents_10_Event)mailItem).Reply += new Outlook.ItemEvents_10_ReplyEventHandler( MailItem_Reply); ((Outlook.ItemEvents_10_Event)mailItem).ReplyAll += new Outlook.ItemEvents_10_ReplyAllEventHandler( MailItem_ReplyAll); ((Outlook.ItemEvents_10_Event)mailItem).Forward += new Outlook.ItemEvents_10_ForwardEventHandler( MailItem_Forward); } } void GenerateItemMessage(object item, string operation) { Outlook.MailItem mi = item as Outlook.MailItem; if (mi != null) { MessageBox.Show(String.Format( "MailItem {0} will be {0].", mi.Subject, operation)); } else { MessageBox.Show(String.Format( "An Outlook item will be {0}.", Operation)); } } void ThisApplication_NewMail() { MessageBox.Show("New mail was received"); } void ThisApplication_NewMailEx(string entryIDCollection) { MessageBox.Show(String.Format( "NewMailEx: {0}.", entryIDCollection)); } void ThisApplication_ItemSend(object item, ref bool cancel) { GenerateItemMessage(item, "sent"); } void MailItem_Send(ref bool cancel) { MessageBox.Show("MailItem Send"); } void MailItem_Reply(object response, ref bool cancel) { GenerateItemMessage(response, "generated as a reply"); } void MailItem_ReplyAll(object response, ref bool cancel) { GenerateItemMessage(response, "generated as a reply to all"); } void MailItem_Forward(object forward, ref bool cancel) { GenerateItemMessage(forward, "generated as a forward"); } } }
Attachment Events
Outlook raises events when attachments are added to an Outlook item and when attachments associated with an Outlook item are read or saved:
Custom Action Events
Outlook enables you to associate custom actions with an Outlook item. A custom action is given a name and some default behaviorfor example, you can create a custom action whose default behavior is to act on the original item or to create a new reply to the existing item. You can also set whether the action is shown as a button or a menu command or both. When the custom action is invoked from the menu or toolbar, the CustomAction event is raised on the associated Outlook item.
Figure 10-2 shows a custom action that has been associated with an Outlook mail item called My custom action. Outlook displays the custom action in the Action menu when an Inspector window is opened on the mail item. It also displays the custom action as a toolbar button.
Figure 10-2. A custom action called My custom action.
Listing 10-9 shows a VSTO Outlook add-in that creates a custom action called My custom action. The CustomAction event is handled to set the subject when the custom action is invoked.
Listing 10-9. A VSTO Add-In That Creates a Custom Action and Handles a Custom Action Event
namespace OutlookAddin1 { public partial class ThisApplication { Outlook.MailItem mailItem; private void ThisApplication_Startup(object sender, EventArgs e) { Outlook.NameSpace ns = this.Session; Outlook.MAPIFolder inbox = ns.GetDefaultFolder( Outlook.OlDefaultFolders.olFolderInbox); foreach (object o in inbox.Items) { mailItem = o as Outlook.MailItem; if (mailItem != null) { break; } } if (mailItem == null) { MessageBox.Show("Couldn't find a mail item."); } else { MessageBox.Show(String.Format( "Connected to the mail item {0}.", mailItem.Subject)); mailItem.CustomAction += new Outlook.ItemEvents_10_CustomActionEventHandler( MailItem_CustomAction); Outlook.Action action = mailItem.Actions.Add(); action.Name = "My custom action"; action.ShowOn = Outlook.OlActionShowOn.olMenuAndToolbar; action.ReplyStyle = Outlook.OlActionReplyStyle.olLinkOriginalItem; } } void MailItem_CustomAction(object action, object response, ref bool cancel) { Outlook.Action action = (Outlook.Action)action; Outlook.MailItem mailItem = (Outlook.MailItem)response; if (action.Name == "My custom action") { mailItem.Subject = "Created by my custom action"; } } } }
Part One. An Introduction to VSTO
An Introduction to Office Programming
Introduction to Office Solutions
Part Two. Office Programming in .NET
Programming Excel
Working with Excel Events
Working with Excel Objects
Programming Word
Working with Word Events
Working with Word Objects
Programming Outlook
Working with Outlook Events
Working with Outlook Objects
Introduction to InfoPath
Part Three. Office Programming in VSTO
The VSTO Programming Model
Using Windows Forms in VSTO
Working with Actions Pane
Working with Smart Tags in VSTO
VSTO Data Programming
Server Data Scenarios
.NET Code Security
Deployment
Part Four. Advanced Office Programming
Working with XML in Excel
Working with XML in Word
Developing COM Add-Ins for Word and Excel
Creating Outlook Add-Ins with VSTO