This topic is relevant for the following:
Product(s): ArcGIS Desktop: All
Version(s): 9.0, 9.1, 9.2
Language(s): VB6, VC++
Experience level(s): Intermediate to advanced
In this section:
A property page is often provided by the ArcGIS framework to allow user interaction with an object or set of objects. Property pages can be found throughout the entire framework, although they are not often found on object diagrams. Many examples described in this book include a property page implementation to allow the user to view and change properties of the custom object.
Property pages allow users to interact with objects by changing the values of their properties without writing code. A property page for a custom object also allows you to link online help files to a particular object and could even be used to brand the object as your third party object.
A property page is not always essential for every custom object, even if other similar objects all have property pages. For example, every ArcObjects symbol has an accompanying property page, but a custom symbol can be created without a property page. In this case, the symbol can be used programmatically as required and will function as expected. The lack of a property page will, however, limit user interaction with the symbol and also highlight the symbol as a nonstandard object to the user.
This section describes the generic process of creating a property page to work within the ArcGIS framework. It identifies the interfaces you must implement and describes how to code the members of these interfaces.
Before creating your own property page, you should know a little about the type of property pages used in ArcObjects, as there are different techniques used by different development environments to create property pages.
Property pages should be a familiar concept, as they are found throughout many applications, development environments, and technologies. To develop a property page for the ArcGIS framework requires a certain set of standard interfaces to be implemented. This may be different from techniques you have used before.
ArcObjects uses a standard COM design, whereby one or many property pages are contained by a property sheet. The property sheet is a dialog box which relates to a certain object or set of objects. Each property page on the property sheet contains controls to view and change the values of a set of related properties or to execute related methods on the object or objects.
The Element Properties dialog box, shown here for a FillShapeElement, is a property sheet containing many property pages, each providing access to a related set of properties of a FillShapeElement.
The range of property pages displayed in a particular property sheet is generally determined dynamically, using a combination of mechanisms. Sometimes a property sheet contains a list of the class identifiers (CLSIDs) for all the property pages it needs to display at runtime. This list of pages can be built dynamically at runtime by reading a component category. In the previous example, the property sheet for a FillShapeElement coclass checks which property pages to display by reading the 'ESRI Element Property Pages' component category.
Many property sheets determine their member property pages
at runtime by using component categories.
For example, the possible property pages for elements are found in the ESRI Element
Property Pages component category.
The same element property sheet is used for all the element coclasses and is, therefore, context sensitiveif you take a look at the ESRI Element Property Pages category (use the Component Browser utility), you will see a number of property pages displayed according to contextthat is, depending on the type of element selected.
So how does the element property sheet decide which particular property pages apply to the type of element selected? The answer lies in the property pages themselves. The property sheet asks each property page whether or not it applies to a particular object and only displays the pages that do apply. More information on how this mechanism works can be found later in this section when the property page interfaces are discussed in more detail.
This model of property sheets and pages is applicable to many customization tasks. In many cases, it is likely that a property sheet already exists for the kind of class you are creating, and you simply need to create a property page to be displayed in this property sheet by ensuring your property page is registered with the appropriate component category and applies to the appropriate kind of object. The sections 'Implementing a property page in Visual Basic' and 'Implementing a property page in Visual C++' describe how to achieve this kind of customization.
Often when creating custom objects, you can create a custom property page to be displayed in an existing property sheet.
You can also instantiate a new property sheet and add any property pages you require to it. See the 'Displaying a Property Sheet' discussion later in this topic.
You can also create an entire property sheet, which has one or many property pages and can itself be extended.
Examples of property pages can be seen, among others, in the LogoMarkerSymbol, VertexLineSymbol, InfoTextElement, and TimestamperClassExtension examples in this book.
In the model thus far, many property pages all apply to a given coclass. For example, the property sheet for an instance of the LineElement coclass displays both the Symbol and the Size and Position property pages, as both apply to the LineElement coclass.
In some cases, the display of property pages is more complex. A property sheet may display one of a number of property pages, which are mutually exclusive and depend on the underlying coclass type.
For example, the Color Browser property sheet (see below) displays a combo box from which you can select different color models. Each color model is represented in ArcObjects by a different color coclass; CMYKColor, GrayColor, HLSColor, HSVColor, and RGBColor. Each coclass has an applicable property page, which is displayed when the appropriate color model is selected in the Color Browser property sheet.
When you select a different color model in the Color Browser, a different embedded property page is displayed, and the Color Browser creates a new coclass of the selected type. The properties of the new color object are set to the nearest approximation of the last selected color. When you click OK in the Color Browser, this new color object is applied to the object being edited.
Embedded property pages are used to handle such situationsthese are property pages that are designed to be contained inside other property pages or property sheets. Creating an embedded property sheet requires little more coding than a standard property sheetsee the following sections for more information.
Generally, embedded property pages for use in a particular page or sheet are registered to a particular component category. For example, the Color Browser displays embedded property pages found in the ESRI Color Property Pages category. All property pages in such a category are considered mutually exclusive.
The Color Browser dialog box is a property sheet that displays a number of embedded property pages. Selecting a different color model in the top combo box displays one of a number of embedded property pages. When the user selects a new color model and the new page is shown, the visual characteristics of the color from the previous page are preserved.
In most cases, certain properties from the object being edited by one property page can be transferred to the object being edited by the new property pagefor example the Color Browser sets an approximation of the last selected color to the newly selected property page.
Another example of an embedded property page is found on the Symbology property page of a layer. In this case, the embedded property pages are displayed within another property page. A different embedded property page is displayed depending on the type of renderer selected in the containing property page.
There are five interfaces that you should be familiar with when creating a property page, all of which are defined in the Framework type library:
This is a standard interface defined by Microsoft as part of its COM implementation in Windows. It is implemented by all the property pages in ArcObjects, providing functionality for both standard and embedded property pages. This interface cannot be implemented in Visual Basic, as it contains several data types not supported by Visual Basic, for example, unsigned long integers. (See IComPropertyPage below for the Visual Basic alternative to this interface.)
This ArcObjects interface provides additional functionality required by embedded property pages in ArcObjects and, notably, provides the method Applies.
This ArcObjects interface was designed for use specifically by Visual Basic developers. It includes similar functionality to that found on the IPropertyPage interface, although you will notice that the members of these two interfaces are not identical. IComPropertyPage also provides functions similar to some found on the IPropertyPageContext interface, although it does not provide all the functionality required by an embedded property page.
This additional ArcObjects interface provides extra functionality to give the property page control over the ability of the user to cancel the property sheet. You can implement this interface in VB, since it inherits directly from IUnknown and replicates the members of IComPropertyPage.
Implementing this interface is optional, depending on whether or not this functionality is required. If you choose to implement it, you must also ensure you implement IComPropertyPage. As most members of IComPropertyPage and IComPropertyPage2 are common, you can delegate the work of these methods to secondary functions.
This interface has similar members to some found on the IPropertyPageContext interface. See the previous section Embedded property pages for more information.
The interfaces you implement for a property page depend upon the development environment you are using. Implementation of property pages in VB and VC++ is discussed in the following sections; however, it is worth noting certain issues.
The interfaces you implement to create a property page vary according to the development environment and the type of property page being created.
Throughout ArcObjects property sheets, the use of IPropertyPage and IPropertyPageContext is being superseded by the use of IComPropertyPage and IComEmbeddedPropertyPage, as they are more flexible for third party developers. However, you may come across property sheets that expect a property sheet to implement IPropertyPage and IPropertyPageContext. In this case, you may want to implement both sets of interfaces. As the interfaces IPropertyPage, IPropertyPageContext, IComPropertyPage and IComEmbeddedPropertyPage share many members in common, you can write generic functions that you can call from all interfaces.
In addition to the interfaces noted here, there are a few specialist property page interfaces you may need to consider implementing if you are creating certain types of property pages.
IRendererPropertyPage should be implemented if you are creating a property page for a custom renderer. ISymbolPropertyPage should be implemented if you are creating a property page for a custom symbol. See 'Extending the display' for examples of implementing both of these interfaces.
It is not recommended that you implement IDataConnectionPropertyPage, IDataConnectionPropertyPage2, or IQueryPropertyPage, as these interfaces do not indicate a complete property page and are designed for internal use only.
A property sheet will clone its target object before passing it to a property page. This allows the property sheet to discard the changes made by all the property pages to the target object if the user cancels the property sheet.
As a Visual Basic developer, you may be accustomed to creating property pages by adding Property Page modules to your project.
To create a property page for an existing ArcGIS property sheet, you will need to take a different approach. You will create a coclass that implements the property page interfaces that ArcObjects expects to find. You will also create a form to contain the user interface components to allow users to interact with the properties of your object.
A property page is implemented in Visual Basic by creating a form module, which contains the user interface for the property page, and a separate class module implementing the required property page interfaces. The two modules are then associated through your code.
Follow these general steps to add a property page implementation to an existing project.
You can now use the internal ScaleHeight and ScaleWidth properties of the form to return the Height and Width of your property page, as required by the IComPropertyPage interface.
Privatem_frmPageAsfrmMyPropertyPageForm
See the following pages for a summary of how to implement property page interfaces.
If the property sheet you intend to add your property page to does not check for IComPropertyPage, you also need to implement IPropertyPage and optionally IPropertyPageContext.
Implement any specialist property page interfaces such as IRendererPropertyPage and ISymbolPropertyPage etc.
Use the variable declared in step 5 to create, show, hide and unload an instance of the property page form as required. Do not forget to add code to translate the values of the controls on your form to the values of the properties of the object you are editing.
For more information on how to register a coclass to a component category, see the topic 'Component Categories'.
| IComPropertyPage members and description | |
|---|---|
| Activate | Called before the Show method when the user selects the property page, making it the current page in the property sheet. Load the previously initialized Form and return the window handle of the page site. |
| Applies | This method is called when the property sheet loads, before the dialog box is displayed. A reference to an ISet object is passed in, which is a collection containing references to the objects to be edited by the property page. The property page is responsible for checking to see if the objects in this set can be edited by the page. Iterate through the set and, using the TypeOf keyword, check the objects. If all the objects required for the page are present, then return true; otherwise, return false. |
| Apply | This method can be used to read the settings from the property page and apply them to the objects you are manipulating with the page (those received in SetObjects), if those changes are not already applied. This method is called when the user clicks either OK or Apply or changes the active property page on the property sheet. See also the IsPageDirty property. |
| Cancel | Called when the cancel button is pressed on the property sheet. |
| Deactivate | Called when the property sheet exits; you should unload the form in this method. |
| Height | Returns the height of the property page, in pixels, from this read-only property, so the property sheet will be sized correctly. |
| HelpContextID | If you have a helpfile, use this read-only property to return the appropriate help context ID number for the property page. |
| HelpFile | If you provide a helpfile for your component, return the filename of the helpfile from this read-only property. |
| Hide | Called when a different page is selected, simply set the Visible property of the form to False. |
| IsPageDirty | The container of the property sheet checks this read-only property to see if the user has made any changes to the property page that have not yet been applied to the object. You should return true if changes have been made to the page; use a global variable to track changes made to the form since the last call toApply. If you return false, the Apply method will not be called upon exit. Called after Hide. |
| PageSite | A reference to an IComPropertyPageSite object is passed in to this method, which has a single method called PageChanged. By calling this method the property page is able to inform the page site that something has changed. Calling this method results in the Apply button becoming enabled. |
| Priority | A number of property pages can be displayed in a property sheet. The pages are ordered by the read-write Priority property. The higher the priority, the sooner the page appears. Priority values are usually between 0 and 100. If you want your page to display as the first page, using a value below 100 allows other pages to override your sheet, if necessary. Check the other property pages that display in the same property sheet as your property page to see which Priority they have. |
| SetObjects | References to the objects to be edited are passed to the page by the SetObjects method in the incoming ISet parameter. Save these objects as global variables. Later, when called to Apply, you can apply the changes specified by the user to the objects passed in. |
| Show | Called after the Activate method when the user selects the property page. Simply set the Visible property on your form to True. |
| Title | This property sets or returns the title of the property page, which is displayed on the page tab. It is recommended that the form caption be used to hold the title. |
| Width | Return the width of the property page in pixels from this read-only property, for the property sheet to be sized correctly. |
| IComPropertyPage2 members and description (see IComPropertyPage for details of other members) | |
|---|---|
| QueryCancel | This method is called when the property page is the currently displayed page and the user clicks the Cancel button before the property sheet is dismissed. Use this method to perform any checks or changes before a user dismisses a property page. Return True to allow the dialog box to be dismissed when the user clicks Cancel, or return False to prevent the Cancel operation. |
| IComEmbeddedPropertyPage members and description | |
|---|---|
| CreateCompatibleObject | This method is called when the user changes the embedded property page that is selected. Create a new object based on the properties of a template object, which is passed in to this method. Note the object returned need not be the same type as the template or even the objects specified in the SetObjects method, or it may be NULL. |
| QueryObject | The property page container will call this method, passing in a reference to an object that applies to the property page, which provides the means for setting the changes from the property page to the object being edited. Set the properties of that object based on the values currently on the property page. Note that the type of object need not match that passed to the SetObjects method. |
Use a member variable in the form module to keep track of any changes made to the form, and use this to return the IComPropertyPage::IsPageDirty value.
Check for invalid user input, such as alphabetic characters instead of numeric characters.
If you need to implement the IPropertyPage interface for compatibility with a particular property sheet, you will find more information on the members of this interface in the following section 'Implementing a property page in Visual C++'.
ArcObjects components separate user interface classes from nonuser interface classesa structure you may want to copyallowing you to upgrade or update sections of your component independently.
In VC++, unlike in Visual Basic, a number of different approaches can be taken to implement a property page for the ArcGIS framework.
The interfaces used by Visual Basic (IComPropertyPage, IComPropertyPage2 and IComEmbeddedPropertyPage) can all be implemented in VC++, providing identical functionality.
Alternatively, the Active Template Library (ATL) property page template classes can be used, providing much of the boilerplate property page code for you. Although this reduces the amount of code you need to write, it does have the slight drawback that the QueryCancel functionality is not provided. This is an optional interface however, and if you don't require this functionality in your property page, using the ATL approach can save you time.
If you choose to implement the ArcObjects IComPropertyPage interface, refer to the tables in the previous section (Implementing a property page in Visual Basic) for details of the interface members. In this case, you may wish to use the following tip to help you return the values of IComPropertyPage::Height and IComPropertyPage::Width.
HRSRC hRsrc = ::FindResource(_Module.m_hInst, MAKEINTRESOURCE(IDD_SAMPLEPROPPAGE), RT_DIALOG);if(hRsrc) { HGLOBAL hGlob = ::LoadResource(_Module.m_hInst, hRsrc); DLGTEMPLATE* pDlgTempl = (DLGTEMPLATE*)::LockResource(hGlob);if(pDlgTempl) _DialogSizeHelper::GetDialogSize(pDlgTempl, &m_size); }
Should you choose to implement the property page using the ATL implementation for IPropertyPage, you must also implement IPropertyPageContext. This provides the key member function Applies, among others.
The following steps take you through the initial setup of your property page ATL project.
It is recommended that you accept the default for all settings apart from Interface, which should generally be set to Custom. For more information on custom interfaces and other details of implementing interfaces, see the 'Coding Interfaces' topic.
Now inspect the generated classyou will find it inherits from the IPropertyPageImpl<> and CDialogImpl<> template classes. The combination of these two classes provides the boilerplate code for the property page. The only method that has been stubbed out to implement is the Apply method, with some commented out sample code. More information about what code you need to put in the members on the IPropertyPage interface can be found in the following table.
| IPropertyPage overrides and description | |
|---|---|
| SetObjects | Set the objects to be edited in the property page. The objects are passed in using a SafeArray of IUknown pointers. The default implementation places these into the m_ppUnk[] array member variable. It can be useful to override this method and set the values into your own member variables using the interfaces you are interested in working with. |
| Show | The default implementation displays the property page. This method can be overridden to provide a place to set the controls in the property page to the values held on the objects being edited. |
| Apply | This method is automatically stubbed out by ATL. It is the place where you read the settings in the property page and update the objects via the interfaces passed in via the SetObjects member function. |
The next step is to add the IPropertyPageContext interface to your class. Use the following steps to add the interface to your class.
More information about what code you need to put in the members on the IPropertyPageContext interface can be found in the following table, which includes only those members that you will typically override in your property page implementation.
| IPropertyPageContext members and description | |
|---|---|
| Applies | This method is called with an ISet containing the interfaces of the objects that are about to be edited via a property sheet. Each page registered within a component category is responsible for checking to see if the objects referenced are suitable for the page. This is performed by iterating through the set and using the TypeOf keyword to check the objects. If all the objects required for the page are present, then return true; otherwise, return false. |
| Cancel | Called when the Cancel button is clicked on the property sheet. |
| CreateCompatibleObjects | Create a new object based on a template object passed in. Note: The object returned need not be the same type as the template or the objects specified in the SetObjects method.) This method is used to create objects suitable for being edited by the property page. A template object passed in can be NULL if the page interacts with a single object. If its not NULL, it can be used to identify the type of object required and allows properties to be copied from the template. |
| GetHelpFile | Use this read-only property to return the filename of a helpfile if you have created one for your page. |
| GetHelpId | Use this read-only property to return the help context ID if implementing help for your page. |
| Priority | A number of property pages can be displayed in a property sheet. By specifying the priority of each property page, you are able to control the order of the pages. The higher the priority, the sooner the page appears. The priority is a read-write property. |
| QueryObject | Called with an object, this method should set the values of the property page on that object. (Note: The type of object need not match that passed into the SetObjects method.) This method is used in embedded property pages when they are not interacting directly with the object, and it provides the means for setting the changes. |
Before attempting to implement a property page using ATL, it is recommended that you review the books in the ATL section of the bibliography. Additional details for the IPropertyPage interface can be found in the Microsoft Developer Network (MSDN) Library.
The next step to get your property page to display as required is to register the class in the appropriate component category. For more information on how to register a coclass to a component category, see the topic 'Component Categories', earlier in this section.
You may decide that your application requires a customized property sheet. This may be because you have created a new component for which no suitable property sheet exists in the ArcGIS framework, or you need to display a number of property pages together and you want your custom property sheet itself to be extensible.
The ArcObjects ComPropertySheet coclass allows you to create a property sheet, and it gives the sheet an object to be edited. The following VBA code demonstrates the basic steps using the IComPropertySheet interface. The principle is exactly the same for VB or VC++ code.
DimpComPropSheetAsesriFramework.IComPropertySheetSetpComPropSheet =NewesriFramework.ComPropertySheetDimpMarkerAsesriDisplay.IMarkerSymbolSetpMarker =NewesriDisplay.SimpleMarkerSymbolDimpMySetAsesriSystem.ISetSetpMySet =NewesriSystem.Set pMySet.Add pMarker pMySet.ResetDimbOKAs BooleanbOK = pComPropSheet.EditProperties(pMySet, Application.hWnd)
Use the ComPropertySheet coclass to create your own property sheet dialog boxes.
Before displaying the property sheet, you can specify which pages you want to appear by using one of two possible approaches:
The component category should contain a list of property page coclasses. Before the property sheet is displayed, each page in the category will be created and have its Applies method called. Every page in the category that applies to the object will be displayed in the property sheet:
DimpUIDAs NewesriSystem.UID pUID.Value = "{818B37C0-F34E-11D2-BC8F-0080C7E04196}" pComPropSheet.ClearCategoryIDs pComPropSheet.AddCategoryID pUID
DimpComPropPageAsesriFramework.IComPropertyPageSetpComPropPage =NewesriDisplayUI.SimpleMarkerPropertyPage pComPropSheet.AddPage pComPropPage
Specify which pages are to appear in the property sheet by using AddCategoryID, AddPage, or both.
By default, if no other pages are specified, the property sheet coclass will automatically check the ESRI Property Pages category for pages that apply to the objects passed to the EditProperties method. All ArcObjects property pages are registered with this category by default.
However, each property page has to be created, checked, and destroyed when checking this entire category. If you use either or both of the approaches above to specify particular property pages, this can improve the display speed of the property sheet.
The ComPropertySheet coclass has one outbound interface, IComPropertySheetEvents, with a single method called OnApply. You may want to call this method to notify other parts of the application that the objects passed to the property sheet have been edited.
Declare the event handler variable globally.
Private WithEventspComPropEventsAsesriFramework.ComPropertySheet
Sink the event handler variable to the property sheet object when the object is created.
Set pComPropEvents = pComPropSheetNow you can call the OnApply method of the interface as required.
DimbOKAs BooleanbOK = (pComPropPage.EditProperties(pMySet, Application.hWnd))IfbOKThenm_pComPropEvents.OnApply
Your property sheet should now be ready to use. Be careful when opening the property sheet with the EditProperties methodif the object passed in is not valid in some way, the property sheet will not be able to display. Check any validity properties on the objects in the Set you passed to EditProperties before calling the method. You may also want to check if any property pages are available by calling the CanEdit method, passing in this same Set.
See Also Design guidelines for property pages.