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 VB, register PipeValidationVB.dll, and double-click
the PipeValidationVB.reg file to register to component categories.
If using VC++, open and build the project PipeValidationVC.dsp to register the DLL and register to component categories.
- Open ArcMap. If using VB, add the PipesVB feature class from the Extending ArcObjects sample data. If using VC++, add the PipesVCpp feature class. These feature classes have been preconfigured with the example's class extension.
- Start editing and select all features in the class. Click the Editor menu and click Validate Features. Two features should be invalid. Select each feature individually and click Validate Features again. The reason for invalidity will be shown.
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 topic, '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.
As Integer Privatem_iMaterialField
As Integer Private Constc_sMaterialField
As String= "MATERIAL"
' HRESULT constant for returning errors
As Long= &H80004005
' Check that it is a linear feature class
' and that both length and material fields are present
SetpFeatureClass = pClassHelper.Class
IfpFeatureClass.ShapeType <> esriGeometryPolyline
ThenErr.Raise E_FAIL, , "Not a linear feature class."
End If DimpLenField
SetpLenField = pFeatureClass.LengthField m_iLengthField = pFeatureClass.FindField(pLenField.Name) m_iMaterialField = pFeatureClass.FindField(c_sMaterialField)
Ifm_iMaterialField = -1
ThenErr.Raise E_FAIL, , "Required field not found: " & c_sMaterialField
End 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 topic.
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.
As StringIObjectClassValidation_ValidateRow = _ IObjectClassValidation_ValidateField(Row, c_sMaterialField)
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.
As String DimsError
As StringsError = ""
IfFieldName = c_sMaterialField
As Double DimsMaterial
As StringdLen = Row.Value(m_iLengthField)
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 = sError