Code for this sample available here. Sorry it’s on GigaSize, but in.solit.us is down, and SkyDrive registration gives me an error code 15.
A couple of days ago I was asked at work about some troubles a team was having with user properties begin written by a form region control and not being able to be read from an add-in. I couldn’t figure out what the problem could be, so I decided to put together a small example that does just that. So here goes another one of those 5-minute quick introduction how-to’s.
I remember back about 5 years ago when I first wrote an Outlook plugin using IDTExtensibility and COM interop and hated it. I got the job done, but it wasn’t a pleasent experience. Look ahead a couple of years and the basic technology for connecting with Office applications has stayed the same. It’s still COM interop on the bottom layer, but we have an advantage. Microsoft has abstracted those dirty layers to some extent (there are lot’s of areas where the ‘old’ stuff still pop ups).
Anyhow creating Outlook plugins (or any Office plugins for that matter) has become very easy in Visual Studio 2008. Simply fire up a new solution, add a Office extensibility (for example Outlook 2007 Add-in) and you are ready to go. In my case I want to add a user property called ‘birthday present’ to my contacts with a form region and everytime Outlook starts I want it to check if there are contacts who have a birthday next week and check if that user property is set (otherwise warn the user, that he needs to get a birthday present). Stupid but simple enough to show this stuff.
First off we need a form region. Add a new item and add ‘Outlook Form Region’. Give it a name, choose an object type for it to appear in and choose a location for it. I chose ‘Adjoining’ an ‘Contact’ to put it on the bottom of the contact form. Design your form region using your Windows Forms skills. Switch to Code view. The FormRegion class is very generic, you have access to a this.OutlookItem which is of type object. Since we know we are working in a contact context, go ahead and create a property to hide the casting:
private ContactItem ContactItem {
get {
if (!(this.OutlookItem is ContactItem))
throw new System.Exception("Not running inside a contact form.");
return this.OutlookItem as ContactItem;
}
}
While we are at hiding some of the dirty stuff and since we will be dealing with a user property from some places in the code let’s go ahead and create a static helper class that returns us a UserProperty that we can work with.
namespace Sample.OutlookFormRegions {
internal static class UserPropertyHelper {
// the id of the field we are working with
private const string UP_BIRTHDAYPRESENT = "up.sample.birthdaypresent";
public static UserProperty GetBirthdayPresentUserProperty(ContactItem contactItem) {
if (contactItem.LastName == "TEST") /* don't want to clog */ {
UserProperty _userProperty = contactItem.UserProperties.Find(UP_BIRTHDAYPRESENT, true /* search custom fields */);
if (_userProperty == null) {
// Add the UP because it does not exist
contactItem.UserProperties.Add(
UP_BIRTHDAYPRESENT, // Name
OlUserPropertyType.olText, // Type
false, // Add it to the folder
0); // Display Format
_userProperty = contactItem.UserProperties.Find(UP_BIRTHDAYPRESENT, true /* search custom fields */);
contactItem.Save();
}
return _userProperty;
} else {
return null;
}
}
}
}
It’s fairly simple. First we use Find to look for the user property. If it does not exist it returns null, so we go ahead and create it. The Add method takes four parameters. The name, the type (OlUserPropertyType), a bool if we want to add it to the folder properties (if we choose yes, we could use and show it in the contacts list view) and a last value regarding the display format. This is dependant on the type. For the text type there is only one display format, therefore 0.
Back to our form region we have two events that we use to load and save the custom data.
private void MyFormRegion_FormRegionShowing(object sender, System.EventArgs e)
private void MyFormRegion_FormRegionClosed(object sender, System.EventArgs e)
In both we use our helper class to get the user property. Don’t forget to call the Save method on the contact to save the data. It is not enough just to set the value of the user property.
UserPropertyHelper.GetBirthdayPresentUserProperty(this.ContactItem);
Now we need our code to check for upcoming birthdays and missing presents.
public void CheckBirthdayPresents() {
m_nsMapi = this.Application.GetNamespace(MAPI);
m_folderContacts = m_nsMapi.GetDefaultFolder(Microsoft.Office.Interop.Outlook.OlDefaultFolders.olFolderContacts);
for (int _contactIdx = 1; /* COM Interop => 1-based */ _contactIdx <= m_folderContacts.Items.Count; _contactIdx++) {
var _contact = m_folderContacts.Items[_contactIdx] as ContactItem;
if (_contact!=null) {
UserProperty _userProperty = UserPropertyHelper.GetBirthdayPresentUserProperty(_contact);
[...] Do the nifty checking here...
}
}
}
First we need to get a namespace, which is basically a session to work in. You can go ahead and use the this.Application.Session object to get the current local MAPI session. Out of bad habit I used the old method via GetNamespace(“MAPI”). It doesn’t buy you anything to do it my way, you can only ever pass “MAPI” into that method and will only ever get the local mapi session. But you know, bad habits are hard to get rid of (for example my funny underscore thing - but that’s a story for a different post). Back to the code.
On that session we can ask for the contacts folder using the GetDefaultFolder and passing in the type for Contacts. We can run through those contacts, but remember this is COM and the collections there are not 0-based but 1-based. So start counting at 1 and finish your loop on smaller OR EQUAL than the length of the array. (I forget that one every time!)
Now we want to add a ribbon to give the user a the possibility of manually starting the check procedure which is done when Outlook starts automatically. Doing this in a ribbon is of course the worst possible place to do this, because the ribbon in Outlook only appears when you open items (e.g. answer an email message, open a calendar item). Ideally you would put the button in a standard old-style menu in the main application, but then I couldn’t show you how to quickly add a ribbon to your app. We will just make the user open a contact and press the button.
Add a new item ‘Ribbon (Visual Designer)’ to your project. First thing you want to do is specify when it appears. Open the ribbon in designer mode, then use the Properties window and navigate to the Ribbon object in the top drop-down.
There you change the RibbonType property to ‘Microsoft.Outlook.Contact’. Now it will appear as a seperate group in the ‘Add-Ins’ tab in the Contact inspector. You can simply drag a button from the toolbox to the designer (remember to use the Office Ribbon Controls). In the click event of the button you call the method we created above. To do that I decided to pass a reference to the add-in to my ribbon and call the public method.
Voila that was simple wasn’t it. As always hope it helps!
PS: More information on form regions available on MSDN here.