Last week I promised to blog a little about my experience to do an add-in for Outlook 2007. In this post I will show an example of how to add a property page to the Options dialog. The result looks something like this (in swedish):

The first thing to do is to catch the OptionsPagesAdd event of the Application object. This event should be set up in the ThisAddIn_Startup event that is part of the ThisAddIn class that VSTO 2 SE creates when you start a new Outlook add-in project.
//Option dialog
this.Application.OptionsPagesAdd += new Microsoft.Office.Interop.Outlook.ApplicationEvents_11_OptionsPagesAddEventHandler(Application_OptionsPagesAdd);
void Application_OptionsPagesAdd(Microsoft.Office.Interop.Outlook.PropertyPages Pages)
{
OptionsPropertyPage page = new OptionsPropertyPage(this);
Pages.Add(page, page.Text);
}
In the event you are supposed to add your property pages to the Pages collection that you receive as an argument. The property pages must implement the Microsoft.Office.Interop.Outlook.PropertyPage interface. I have created an base class for all property pages as an user control that implements the interface and provides some other useful features.
[System.Runtime.InteropServices.ComVisible(true)]
public partial class PropertyPageBase : UserControl, MSOutlook.PropertyPage
{
private MSOutlook.PropertyPageSite site;
private bool isDirty;
public PropertyPageBase()
{
InitializeComponent();
}
protected virtual void OnApply() { if (IsDirty) MessageBox.Show("Override OnApply!"); }
protected override void OnLoad(EventArgs e)
{
Type type = typeof(UserControl);
Type oleType = type.Assembly.GetType("System.Windows.Forms.UnsafeNativeMethods+IOleObject");
if (oleType == null) thrownewInvalidOperationException("Could not get 'System.Windows.Forms.UnsafeNativeMethods+IOleObject'.");
System.Reflection.MethodInfo method = oleType.GetMethod("GetClientSite");
if (method == null) thrownewInvalidOperationException("Could not get method 'IOleObject.GetClientSite'.");
site = method.Invoke(this, null) as MSOutlook.PropertyPageSite;
base.OnLoad(e);
}
[Browsable(false)]
public bool IsDirty
{
get { return isDirty; }
set
{
if (isDirty != value)
{
isDirty = value;
if (site != null) site.OnStatusChange();
}
}
}
#region PropertyPage Members
public void Apply()
{
OnApply();
this.isDirty = false;
}
bool MSOutlook.PropertyPage.Dirty
{
get { returnthis.IsDirty; }
}
public virtual void GetPageInfo(refstring HelpFile, refint HelpContext)
{
}
#endregion
}
Worth noting in the class above is that it of course must be visible to COM which is set by the ComVisible attribute of the class. There is a hack in the OnLoad that I found
here, which is also a complete property page sample. You need the site to be able to force Outlook to call the IsDirty property of the PropertyPage interface and if you return true from the property it will enable the Apply-button.
In the inheriting class you are supposed to set the IsDirty property when something changes and override the OnApply method to do your own saving. In my case I write the settings to a file in the users roaming profile.