Syntax for Outlook property and form control values and events
One of the key stumbling blocks for beginning Outlook programmers is how to change and retrieve data in Outlook items. Several different syntaxes apply, depending on whether you are working with the three basic entities on an Outlook form:
- a built-in property
- a user-defined property
- a control and its Value and other properties
An important related topic covered on this page is how to write code to handle the user's interaction with the form. For example, you may want to change the appearance of a control or validate a value, depending on what the user enters.
A key concept is that of bound and unbound controls. Only data entered in a bound control is stored when the user saves the item. Data entered in an unbound control is discarded unless you include code behind the form to save it to an Outlook property. To determine whether a control is bound and if so, to what property, use the controls at the top of the Value tab of the Properties dialog for the control:
I commonly see confusion over where to use the property name and where to use the name of the control that displays the data from that property on a form. For example, I'll see an expression such as Item.UserProperties("TextBox38"). No one names a property "TextBox38." That's more typically the name of a control. The code needs to either refer to the control -- objControls("TextBox38") -- or refer to the property -- Item.UserProperties("Expense").
When should you use the property name and when should you use the control name? Usually, you'll use the property name if you're working with bound controls and want to read or set property values or react to changes in property values. Use the control name if you're setting properties for the control (like Visible) or putting data into or getting data out of an unbound control.
Also note that the PropertyChange and CustomPropertyChange events fire on every property change. You cannot specify what property you want them to monitor by putting it as an argument in your subroutine. Instead, as the examples show, you should use a Select statement block to lay out code for handling different properties. If you need to monitor just one property change, you could replace the Select block with an If ... End If block to test for the Name of the property.
To access the value of a built-in Outlook property, you must know the name of the property. Do not assume that the actual property name is the same as the name you see in the Field Chooser. You can look up properties in the Object Browser in VBA or in the code window of an Outlook form in design mode. Just press F2.
Once you know the property name, you can use either syntax to get the value:
MyValue = objItem.propname
MyValue = objItem.ItemProperties(propname)
where objItem is an object variable representing an Outlook item and propname represents the name of the property. If you are writing code behind an Outlook form, the current item -- the one the code is running for -- is the Item intrinsic object, so you can use:
MyValue = Item.propname
On an Outlook form, to react to changes in the values of built-in properties, use the PropertyChange event with a Select Case block:
The PropertyChange event fires only after the user presses Tab or Enter or otherwise moves the focus to another property. On some types of items, changing one property causes several other properties to change as well. To test what built-in properties change in response to particular user actions, try this code on an Outlook form:
The PropertyChange event does not fire for the Body property, which represents the main block of text on an item (shown in the Field Chooser as either Note or Message, depending on the type of item). To track changes in the Body property, you can want to put code in the Item_Open event handler to store the initial value of Body in a module-level variable, so you can compare it later with the user's changes.
To access the value of a user-defined Outlook property, you need to know the name of the property. This is the name you assigned when you created the property. You'll see it on the All Fields tab in form design. Use the UserProperties or ItemProperties collection to work with it:
MyValue = objItem.UserProperties("propname")
MyValue = objItem.ItemProperties("propname")
where objItem is an object variable representing an Outlook item and propname represents the name of the property.
If you're writing code behind an Outlook form, the current item -- the one the code is running for -- is the Item intrinsic object, so you can use:
MyValue = Item.UserProperties("propname")
Keywords properties are an exception to the above syntax. Their values cannot be accessed directly through UserProperties or ItemProperties. Instead, you can use one of the techniques discussed on these pages:
On an Outlook form, to react to changes in the values of custom properties, use the CustomPropertyChange event with a Select Case block. It works just like the PropertyChange event shown above:
Do not replace "Name" in the argument for the CustomPropertyChange event or the Select Case statement with the name of a particular property. This one event fires for every custom property. Use the Select Case block to handle the individual properties, starting with a Case statement for each property whose value change you are interested in. Within each Case block, you will probably need to test the value of the property that changed with either an If ... End If block or another Select block.
The inner Select Case statement above example above shows the structure for checking the value of a string property. The syntax would be slightly different, of course, for a date/time, numeric, or Boolean property.
The CustomPropertyChange event fires only after the user presses Tab or Enter or otherwise moves the focus to another control. If you need to handle a custom property change in all situations, you may need to include that code in your Send, Write, and other event handlers.
One oddity: If you can successfully add a property from another type of item to a custom form (and that's a big IF -- very few properties can transfer between items), Outlook automatically creates a corresponding UserProperty. That property does not, however, behave like a normal UserProperty. It doesn't fire a CustomPropertyChange event, and the value of the property may not change when you expect it to. See task Item.UserProperties("Cc") changing after creating a message object for a discussion of such a case.
The third type of value that you may need to access, particularly in Outlook form code, is the data that a user has entered into an unbound control on a form. (Again, unbound means that the text box or other control is not tied to an Outlook property.) Outlook uses a peculiar syntax to get the value of a control, more complicated than a VB or VBA programmer might be accustomed to. You need to know not just the name of the control, but also the name of the page on the Outlook form where it appears. Get the name of the control by right-clicking the control and viewing its Properties dialog. Then use this syntax:
where "My Page" is the name of the page and "TextBox1" is the name of the control.
The only event supported by controls on an Outlook form is the Click event. For example, you can use the Click event to track when a user selects a new value from an unbound drop-down list (combo box):
However, not all unbound controls support the Click event. (For bound controls, you must use the PropertyChange and CustomPropertyChange events discussed above.) The Click event fires on a drop-down list combo box, but not if the user types a value into a combo box that has its style set to DropDownCombo (0). It fires for label (see To create a hyperlink on an Outlook form for an application), frame (when the user clicks empty space inside the frame), list box, check box, option button and command button controls, but not for text box or spin button controls. For list boxes, there must be at least one item in the list, and the user must click on a list item (not in any blank area in the list box), in order for the Click event to fire.
A common application of the Click event is to use a checkbox or option buttons to change the appearance of another control. For example, you might want to change the items displayed in a list or combo box or display a group of items that were previously hidden. In this example, chkNeedCheck is an unbound checkbox and frmCheckData is a frame on the General page containing bound controls where the user can enter additional information.
Clicking on the chkNeedCheck checkbox toggles the frmCheckData's Visible property, alternately showing and hiding the frame and all the controls it contains. If you want to disable and enable the control, use the Enabled property instead of Visible. Note that such UI changes are not persisted when the user saves the item. If you want the UI to look the same when the user opens the item, then you need to store information about the state of the UI in one or more custom properties and use code in the Item_Open event handler to adjust the UI, based on the stored "state" information. In the above example, the easiest solution would be to bind the check box to a custom yes/no (Boolean) property. That would, of course, require using CustomPropertyChange event rather than the control's Click event.
For a demonstration of the Click event generated by unbound option buttons, download Form Controls Demo.zip (6kb, 30 Aug 04), unzip it, open the .oft file with the Tools | Forms | Choose Form command, and publish that form. Then run the published form. Also see How to make a checkbox show and hide a frame.
Besides the Click event, you can use the Item_Write, Item_Close or Item_Send event to process the information in the unbound controls. Note, however, that if the user changes only the data in an unbound control -- and not the data in any bound control -- Item_Write will not fire when the user clicks Save.
You can use the PropertyChange and CustomPropertyChange events to help you understand what happens when the user interacts with form controls showing both built-in and custom properties. Just add this code to your form to have a message box pop up every time a property changes. (For example, guess how many properties change when you change the status of a task to Completed.)
The Click event for an unbound control fires when you set the Value of the control. If you initialize the value of a control in the Item_Open event of a form and then use the control's Click event to set the value of an Outlook property, you may want to use code like this to make sure that the property is set only when the user clicks the control, not during form initialization. In this example, cmbCategories is a combo box on a Contact form's General page and UserCat2 is a custom property:
From the Outlook 2007 Developer Reference:
PropertyAccessor is a new object in Outlook 2007 that allows developers to get and set the values of hidden properties that were previously accessible only with additional APIs, such as Extended MAPI, CDO 1.21, or Redemption. You can also use PropertyAccessor with built-in and custom properties. To learn about it, begin with this article from Outlook 2007 Developer Reference: