ArcGIS SDK  

Extending ArcObjects

Tabbed Feature Inspector Example

In this section:

  1. The case for a tabbed feature inspector
  2. Creating a TabbedFeatureInspector

Tabbed feature inspector example

Example Code Click here.

Description This project provides a custom feature inspector that shows the standard feature inspector in one tab and on a second tab, if appropriate, an image corresponding to the feature.

Design Subtype of FeatureClassExtension abstract class.

License required ArcEditor

Libraries Editor, Geodatabase, and System

Languages Visual Basic

Categories ESRI GeoObject ClassExtensions

Interfaces IClassExtension, IFeatureClassExtension, IObjectInspector, and IObjectClassEvents.

How to use

    1. Register TabbedInspectorVB.dll, and double-click the TabbedInspectorVB.reg file to register to component categories.
    2. Open ArcMap and add the WildlifeSightings feature class (from the FeatureInspector feature dataset) from the ExtendingArcObjects.mdb personal geodatabase that is installed in the Data folder of the Developer Kit Samples. This feature class is preconfigured with the class extension implementing the custom feature inspector.
    3. Start editing, select some of the wildlife points and open the Attributes dialog box to inspect the tabbed display.

The case for a tabbed feature inspector

Imagine a feature class that has a Photo attribute, which is a geodatabase raster field containing an image of the feature. When editing the feature class, you can view the image by clicking the Photo field in the Feature Inspector and clicking the button, which should then be displayed by the field name.

Your users may find that this is not the most convenient way of viewing the raster. They would prefer to see the image, if present, shown on another tab in the Attributes dialog box, rather than via the standard button on the dialog box.

In this example, the right panel of the Attributes dialog box is customized to have a tab that displays the image, rather than the image being available via the standard button within the right pane of the Attributes dialog box.

Creating a subtype of ObjectClassExtension and ObjectInspector

By reviewing the Editor object model diagram, you can see that the existing FeatureInspector and DimensionInspector classes inherit from the ObjectInspector abstract class and implement the IObjectInspector interface.


A custom feature inspector is a special kind of object class extension. To create a custom feature inspector, you must create a subtype of the abstract class ObjectClassExtension by implementing the IClassExtension and IObjectClassExtension interfaces. You can find the ObjectClassExtension abstract class on the Geodatabase object model diagram.


Class extensions and their deployment are described in Chapter 7, 'Customizing the geodatabase', so this section will concentrate on aspects relevant to feature inspectors only.


Creating a TabbedFeatureInspector

To solve the requirements of this example, you will create a subtype of ObjectClassExtension by implementing IClassExtension and IObjectClassExtension.

To provide the inspector functionality, you will also implement IObjectInspector. To respond to changes in the feature being edited, you will also sink events from the IObjectClassEvents interface.


Add to your project a Form with a tab control which has two tabs. One tab will contain the default feature inspector—call this tab Attributes, and add a picture box to fill the tab. Call the other tab Image, and add a MapControl to fill the tab—this will be used to display the raster appropriate to a feature.

Note that you do not always need to include the default inspector; you may create a simpler component that shows just a plain untabbed form.

Implementing IObjectInspector

A feature inspector is contained in the right panel of the Attributes dialog box, so you need inform that dialog box of what you would like to display inside it. This is done by supplying the IObjectInspector::hWnd property with the handle of your form. Instead of passing the handle of the form, the example passes the handle of a PictureBox control on which the rest of the form objects are placed. It would be ideal to pass the window handle of the tab control, but in this case the SSTab control does not have a Resize event which, as will be explained later, is necessary for this example.

[Visual Basic 6]
Private Property Get IObjectInspector_hWnd() As OLE_HANDLE
  ...
  IObjectInspector_hWnd = frmInspector.picWhole.hwnd
End Property

The default feature inspector is made by cocreating from the FeatureInspector class. It is best to do this initialization in the hWnd property—placing this code in Class_Initialize or IClassExtension::Init would be inefficient since there are many occasions when your feature class will be opened in a context that does not involve the Attributes dialog box.


After creating the default inspector, you must hook its window into your form at run time. This can be done by calling two Win32 API functions: SetParent, followed by ShowWindow.

[Visual Basic 6]
Private Property Get IObjectInspector_hWnd() As OLE_HANDLE
  ' If form not already loaded, do initialization
  If Not m_bFormLoaded Then
    Load frmInspector
    If m_pDefaultInspector Is Nothing Then
      Set m_pDefaultInspector = New FeatureInspector
    End If
    ' hook the default inspector's window into the form
    SetParent m_pDefaultInspector.hwnd, frmInspector.picDefault.hwnd
    ShowWindow m_pDefaultInspector.hwnd, SW_SHOW
    ' pass the default inspector to the form (needed for resizing)
    frmInspector.Inspector = m_pDefaultInspector
    m_bFormLoaded = True
  End If
  
  IObjectInspector_hWnd = frmInspector.picWhole.hwnd
End Property

IObjectInspector::Inspect is triggered every time the active feature in the Attributes dialog box is changed or another feature is selected via the map. Note that an enumeration of objects is supplied as a parameter. Normally, just a single feature will be present in the enumeration, but if the area at the top of the list in the Attributes dialog box is selected, then all the features in the dialog box are supplied in the enumeration. Note that in the latter case the default inspector applies edits to all the selected features at once.

If the user highlights the area at the top of the list of selected features, all the features are passed to IObjectInspector::Inspect. Normally just the single active feature is supplied.

In the example it would be inappropriate to show the image tab when no single feature is active, so different code is executed if there is more than one feature in the enumeration.

[Visual Basic 6]
Private Sub IObjectInspector_Inspect(ByVal Objects As esriEditor.IEnumRow, ByVal pEditor As esriEditor.IEditor)
  m_pDefaultInspector.Inspect Objects, pEditor
  
  ' Determine if more than one object is active in the attribute window
  ' If so, disable the image tab
  Objects.Reset
  Dim pObject As IObject
  Set pObject = Objects.Next ' first object
  If Not Objects.Next Is Nothing Then
    Call SetImageTabVisible(False)
  Else
    ' get value of image field, and load picture with it
    If IsNull(pObject.Value(m_iImageField)) Then
      Set m_pRasterValue = Nothing
      Call SetImageTabVisible(False)
    Else
      Set m_pRasterValue = pObject.Value(m_iImageField)
      Call LoadImageTab
    End If
  End If
End Sub

You can improve performance when there are multiple features to be updated. From IEnumRow you can QI to IEnumIDs. After looping through the IDs you can call IFeatureClass::GetFeatures, which will retrieve the features in one call instead of fetching them one at a time with IEnumRow::Next.

There is one more IObjectInspector method that needs consideration. Copy is triggered when the user selects the Paste command on the context menu of the Attributes dialog box. The default feature inspector implements Copy by performing an edit operation to copy all the values from the supplied row to the row being edited. In the example, the request is just passed on to the default inspector.

Responding to data changes

It is possible that a user will change the photo attribute using the default inspector in the first tab. In this case the image on the second tab should be reloaded as appropriate. The best way of catching this edit event is by implementing IObjectClassEvents , since, like IObjectInspector, this is also a class extension interface.

The example checks that the feature inspector form is loaded to allow for edits being made when the Attributes dialog box is not present.

[Visual Basic 6]
Private Sub IObjectClassEvents_OnChange(ByVal obj As esriGeodatabase.IObject)
  If m_bFormLoaded Then
    If IsNull(obj.Value(m_iImageField)) Then
      Set m_pRasterValue = Nothing
      Call SetImageTabVisible(False)
    Else
      Dim pCurValue As IRasterValue
      Set pCurValue = obj.Value(m_iImageField)
      If Not pCurValue Is m_pRasterValue Then
        Set m_pRasterValue = pCurValue
        Call LoadImageTab
      End If
    End If
  End If
End Sub

For more information about IObjectClassEvents , see the section on class extensions in Chapter 7, 'Customizing the geodatabase'.

Resizing the feature inspector

When the Attributes dialog box is resized by the user, the window returned by IObjectInspector::hWnd is automatically resized. In the example, the picture box containing the other form objects is automatically resized, but code to resize the default inspector, tabs, and image picture box is required. The default inspector window is not a member of the Visual Basic project, so it must be resized with a Win32 API call to make it the same size as its picture box container.

[Visual Basic 6]
Private Declare Function SetWindowPos Lib "user32" (ByVal hwnd As Long, _
 ByVal hWndInsertAfter As Long, ByVal X As Long, ByVal y As Long, _
 ByVal cx As Long, ByVal cy As Long, ByVal wFlags As Long) As Long
...
Private Sub picWhole_Resize()
  ...
  picDefault.ScaleMode = vbPixels
  lSuccess = SetWindowPos(m_pDefaultInspector.hwnd, 0, 0, 0, _
   picDefault.ScaleWidth, picDefault.ScaleHeight, _
   SWP_NOMOVE Or SWP_NOZORDER)
  picDefault.ScaleMode = vbTwips
End Sub

Now you should be able to edit the WildlifeSightings feature class and see the rasters stored with each feature in the Attribute dialog box.


Back to top

Go to example code