In this section:
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
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.
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.
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 inspectorcall this tab Attributes, and add a picture box to fill the tab. Call the other tab Image, and add a MapControl to fill the tabthis 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.
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.
Private Property GetIObjectInspector_hWnd()AsOLE_HANDLE ... IObjectInspector_hWnd = frmInspector.picWhole.hwndEnd Property
The default feature inspector is made by cocreating from the FeatureInspector class. It is best to do this initialization in the hWnd propertyplacing 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.
Private Property GetIObjectInspector_hWnd()AsOLE_HANDLE' If form not already loaded, do initializationIf Notm_bFormLoadedThenLoad frmInspectorIfm_pDefaultInspectorIs Nothing Then Setm_pDefaultInspector =NewFeatureInspectorEnd If' hook the default inspector's window into the formSetParent 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 IfIObjectInspector_hWnd = frmInspector.picWhole.hwndEnd 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.
Private SubIObjectInspector_Inspect(ByValObjectsAsesriEditor.IEnumRow,ByValpEditorAsesriEditor.IEditor) m_pDefaultInspector.Inspect Objects, pEditor' Determine if more than one object is active in the attribute window' If so, disable the image tabObjects.ResetDimpObjectAsIObjectSetpObject = Objects.Next' first objectIf NotObjects.NextIs Nothing Then CallSetImageTabVisible(False)Else' get value of image field, and load picture with itIfIsNull(pObject.Value(m_iImageField))Then Setm_pRasterValue =Nothing CallSetImageTabVisible(False)Else Setm_pRasterValue = pObject.Value(m_iImageField)CallLoadImageTabEnd 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.
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.
Private SubIObjectClassEvents_OnChange(ByValobjAsesriGeodatabase.IObject)Ifm_bFormLoadedThenIfIsNull(obj.Value(m_iImageField))ThenSetm_pRasterValue =NothingCallSetImageTabVisible(False)ElseDimpCurValueAsIRasterValueSetpCurValue = obj.Value(m_iImageField)If NotpCurValueIsm_pRasterValueThenSet m_pRasterValue = pCurValueCallLoadImageTabEnd If End If End If End Sub
For more information about IObjectClassEvents , see the section on class extensions in Chapter 7, 'Customizing the geodatabase'.
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.
Private Declare FunctionSetWindowPosLib"user32" (ByValhwndAs Long, _ByValhWndInsertAfterAs Long,ByValXAs Long,ByValyAs Long, _ByValcxAs Long,ByValcyAs Long,ByValwFlagsAs Long)As Long...Private SubpicWhole_Resize() ... picDefault.ScaleMode = vbPixels lSuccess = SetWindowPos(m_pDefaultInspector.hwnd, 0, 0, 0, _ picDefault.ScaleWidth, picDefault.ScaleHeight, _ SWP_NOMOVEOrSWP_NOZORDER) picDefault.ScaleMode = vbTwipsEnd 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.
Go to example code