In this section:
Example Code Click here.
Description This project provides a custom validation of attributes, such that for any feature with a length greater than 10 meters, the valid values for MATERIAL are 'Coated Steel' or 'PVC'.
Design Subtype of FeatureClassExtension abstract class
License ArcEditor or above
Libraries Geodatabase, Geometry, and System
Languages Visual Basic, Visual C++
Categories ESRI GeoObject ClassExtensions
Interfaces IClassExtension, IFeatureClassExtension, and IObjectClassValidation
How to use
If using VC++, open and build the project PipeValidationVC.dsp to register the DLL and register to component categories.
Imagine a network of water pipes. Pipes longer than 10 meters may only be made of PVC or coated steel, but shorter pipes may be made of many different materials. You would like to apply an attribute rule that ensures the material type as just described.
Pipes longer than 10 meters may only be made of coated steel or PVC.
The valid materials are dependent on the pipe length. The usual way to implement dependent validation is with subtypes, since each subtype within the object class can have a separate validation rule, and this can all be configured in ArcCatalog without any programming. However, in the example the dependency is on the pipe length, which is not a suitable attribute on which to base subtypes since there is no set of discrete values. A solution would be a custom attribute rule that validates objects on a combination of fields (for example, length and material) rather than just one field as normal. In the geodatabase the way to implement this behavior is with a class extension.
Class extensions are the main way of providing custom geodatabase behavior. There are only two interfaces you must implement: IClassExtension and IObjectClassExtension. The latter interface is trivial, it just provides an identity for your extension. IFeatureClassExtension is a similar required identity interface if your extension applies to feature classes only. If you don't implement IObjectClassExtension, your extension will still work, but it won't conform to what is presented to developers on the ESRI object model diagrams.
Class extensions are not a way of making subclasses of the standard ObjectClass. Instead they provide an extension to the capabilities of ObjectClass.
The COM class that implements the class extension must be registered to the ESRI GeoObject Class Extensions component category. For details on how to apply a class extension to your data, see the next section in this chapter, 'Managing Class Extensions'.
This is a simple interface, but possibly the most crucial. If there is an error in your code here, none of your users will be able to access the data in the object class.
The Init method is fired every time your object class is opened. If your object class is contained within a feature dataset, Init will fire as soon as any of the other feature classes are opened.
Within a feature dataset, if one feature class is opened, all the others are opened as well. This can cause your class extension's Init method to fire when you might not expect it.
You will typically use Init to initialize objects you want to store at the class level. The Pipe Validation example stores the index positions of the important fields to avoid recalculating them each time the field is used.
ImplementsIClassExtensionImplementsIObjectClassExtensionImplementsIFeatureClassExtensionImplementsIObjectClassValidationPrivatem_iLengthFieldAs Integer Privatem_iMaterialFieldAs Integer Private Constc_sMaterialFieldAs String= "MATERIAL"' HRESULT constant for returning errorsPrivate ConstE_FAILAs Long= &H80004005Private SubIClassExtension_Init(ByValpClassHelper _AsesriGeoDatabase.IClassHelper, _ByValpExtensionPropertiesAsesriSystem.IPropertySet)' Check that it is a linear feature class' and that both length and material fields are presentDimpFeatureClassAsIFeatureClassSetpFeatureClass = pClassHelper.ClassIfpFeatureClass.ShapeType <> esriGeometryPolylineThenErr.Raise E_FAIL, , "Not a linear feature class."End If DimpLenFieldAsIFieldSetpLenField = pFeatureClass.LengthField m_iLengthField = pFeatureClass.FindField(pLenField.Name) m_iMaterialField = pFeatureClass.FindField(c_sMaterialField)Ifm_iMaterialField = -1ThenErr.Raise E_FAIL, , "Required field not found: " & c_sMaterialFieldEnd If End Sub
To run your class extension in the Visual Basic debugger, you will need a debug startup executable that registers your class to the correct component categories, then starts the appropriate application such as ArcMap.
For more details, see the description of the Compile and Register Add-In in the Component Categories section of Chapter 2, 'Developing Objects'.
There are two parameters to Init. The second, the class extension properties, is discussed in the next example. The first parameter, the class helper, is an intermediate object used to prevent circular references between an object class and a class extension. You should not keep a class-level variable referring to the object class; instead, keep a reference to this class helper object.
Note the error handling in the exampleno message boxes are used to report the errors. You should avoid all user interface facilities in your class extension, since the geodatabase is independent of the user interface. Someone may want to use your object class extension from a nongraphical environment such as the command line, in which case message boxes would be inappropriate. It is better to pass the error back to the client application. In the example an HRESULT error number is used. This means that clients to the class extension will be able to handle the error appropriately whether they are written in Visual Basic or Visual C++.
Avoid unnecessary user interface functions in your class extension.
IObjectClassValidation provides custom validation of objects in addition to geodatabase validation of domains, relationship rules, and connectivity rules. After successfully completing all native validation within the geodatabase, the ValidateRow method is called. Effectively, this is the last type of validation performed when validating an object.
The ValidateRow method is called by an object's IValidate::Validate method and by the Validate methods on the IValidation interface of the associated object class. When implementing ValidateRow you will typically pass on the request to ValidateField, which provides the finer-grained validation.
Private FunctionIObjectClassValidation_ValidateRow(ByValRowAs_ esriGeodatabase.IRow)As StringIObjectClassValidation_ValidateRow = _ IObjectClassValidation_ValidateField(Row, c_sMaterialField)End Function
The ValidateField method is called when IValidate::GetInvalidFields is called on an object of the associated object class. For both ValidateField and ValidateRow, if the field or row is invalid you should return an appropriate error string; otherwise, return a zero-length string.
Private FunctionIObjectClassValidation_ValidateField(ByValRowAs_ esriGeoDatabase.IRow,ByValFieldNameAs String)As String DimsErrorAs StringsError = ""IfFieldName = c_sMaterialFieldThen DimdLenAs Double DimsMaterialAs StringdLen = Row.Value(m_iLengthField)IfIsNull(Row.Value(m_iMaterialField))ThensMaterial = ""ElsesMaterial = Row.Value(m_iMaterialField)End If IfdLen > 10# _And(sMaterial <> "PVC"AndsMaterial <> "Coated Steel")ThensError = "Value for " & c_sMaterialField & " is invalid." & _ vbNewLine & "If length is greater than 10m," & _ " only PVC and Coated Steel are valid."End If End IfIObjectClassValidation_ValidateField = sErrorEnd Function
Go to example code
See Also About Class Extensions, Managing Class Extensions, Timestamper Class Extension Example, Class Extensions and Relationship Classes, and Class Extensions for Annotation and Dimensions.