Creating Class Extensions
Creating Class Extensions
Creating Class Extensions
Creating class extensions
Summary
A class extension allows custom behavior to be applied to object classes and feature classes in a geodatabase. Typically, a
class extension is used for tasks, such as implementing validation rules that are not possible outofthebox, custom
rendering in a map, and listening for class events. Class extensions are the most important type of geodatabase
customization.
This topic explains what class extensions are typically used for and how to perform each step in creating a class extension,
from its initial creation in Visual Studio through implementation, component category registration, and application to a new
or existing object class. It also explains how to implement each class extension interface (required and optional), create
custom description classes, and effectively manage and use extension properties.
In this topic
Common uses of class extensions
Creating a class extension
Applying a class extension
Implementing interfaces
IClassExtension
Working with extension properties
IObjectClassExtension and IFeatureClassExtension
IObjectClassEvents
IObjectClassValidation
IObjectClassInfo and IObjectClassInfo2
IRelatedObjectClassEvents and IRelatedObjectClassEvents2
IConfirmSendRelatedObjectEvents
IObjectInspector
IFeatureClassEdit
IFeatureClassDraw
Creating custom class descriptions
Common uses of class extensions
Use class extensions to customize geodatabase behavior that applies to a single object class or feature class. The following
includes examples of functionality that can be implemented with class extensions:
http://help.arcgis.com/en/sdk/10.0/arcobjects_net/conceptualhelp/index.html#//000100000201000000 1/36
11/6/2015 Creating class extensions
Handling events triggered by object creation, deletion, or modification—The IObjectClassEvents interface can be
implemented to obtain this functionality.
Validation rules too specific or complex to be applied outofthebox—The IObjectClassValidation interface allows
extensions to customize the validation process.
Handling events from related datasets—The following interfaces can be used, depending on the requirements of the
class extension: IRelatedObjectClassEvents, IRelatedObjectClassEvents2, and IConfirmSendRelatedObjectEvents.
Defining custom split policies for relationship classes—The IFeatureClassEdit interface can be used and despite its
name, it can be used with feature or object class extensions.
Specifying custom renderers for feature classes—The IFeatureClassDraw interface can be implemented to associate a
custom renderer with a feature class, with the option of making it the exclusive renderer for the class.
Storage of data associated with the class, such as text, numbers, or objects—This data can be stored in member
variables and used by public and private extension members. These keyvalue pairs are referred to as class extension
properties.
Methods and properties defined by a custom interface (or no interface) can be implemented by a class
extension—This is a useful place to define properties to access and modify extension properties or to implement methods
for extension specific behavior.
Creating a class extension
When creating a class extension, the following attributes and methods are required (or recommended) for the extension to
function properly:
Three attributes from the System.Runtime.InteropServices namespace: globally unique identifier (GUID), ClassInterface,
and ProgID
Component Object Model (COM) register and unregister methods, which call ArcGIS component category registration and
unregistration methods
The following code example shows the attributes:
[C#]
[Guid("a78421ba‐0d38‐4104‐be58‐b049b16f637c")][ClassInterface
(ClassInterfaceType.None)][ProgId("SampleClassExt.SampleClassExtension")
][ComVisible(true)]
public class SampleClassExtension: IClassExtension, IObjectClassExtension
{
// Class members here…
}
[VB.NET]
<Guid("a78421ba‐0d38‐4104‐be58‐b049b16f637c"), _
ClassInterface(ClassInterfaceType.None), _
http://help.arcgis.com/en/sdk/10.0/arcobjects_net/conceptualhelp/index.html#//000100000201000000 2/36
11/6/2015 Creating class extensions
ClassInterface(ClassInterfaceType.None), _
ProgId("ClassExtensionArticle.SampleClassExtension"), _
ComVisible(True)> _
Public Class SampleClassExtension
Implements IClassExtension, IObjectClassExtension
' Class members here…
End Class
The GUID's attribute parameter should be randomly generated by Visual Studio or another application. The ProgID's attribute
parameter should be the fully qualified name of the class. Copying and pasting the values in the preceding code example without
modification is not recommended.
The following code example shows the COM register and unregister methods:
[C#]
[ComRegisterFunction()][ComVisible(false)] static void RegisterFunction(Type
registerType)
{
string regKey = string.Format("HKEY_CLASSES_ROOT\\CLSID\\{{{0}}}",
registerType.GUID);
GeoObjectClassExtensions.Register(regKey);
}
[VB.NET]
<ComRegisterFunction(), ComVisible(False)> _
Shared Sub RegisterFunction(ByVal registerType As Type)
Dim regKey As String = String.Format("HKEY_CLASSES_ROOT\CLSID\{{{0}}}", registerType.GUID)
GeoObjectClassExtensions.Register(regKey)
End Sub
<ComUnregisterFunction(), ComVisible(False)> _
Shared Sub UnregisterFunction(ByVal registerType As Type)
Dim regKey As String = String.Format("HKEY_CLASSES_ROOT\CLSID\{{{0}}}", registerType.GUID)
GeoObjectClassExtensions.Unregister(regKey)
End Sub
Although it is possible to manually add these methods, ArcGIS and Visual Studio provide the functionality for a class extension
to be generated automatically. See the following steps:
1. On the Solution Explorer, rightclick the project that contains the class extension, click Add, then click New Item.
The Add New Item dialog box appears. See the following screen shot:
http://help.arcgis.com/en/sdk/10.0/arcobjects_net/conceptualhelp/index.html#//000100000201000000 3/36
11/6/2015 Creating class extensions
2. On the Add New Item dialog box, click ArcGIS under the Categories pane and click ArcGIS Class under the Templates
pane. Type an appropriate name for the class extension in the Name text box and click Add. The ArcGIS Add Class
Wizard dialog box appears. See the following screen shot:
http://help.arcgis.com/en/sdk/10.0/arcobjects_net/conceptualhelp/index.html#//000100000201000000 4/36
11/6/2015 Creating class extensions
3. On the ArcGIS Add Class Wizard, under Customization Group, click the first dropdown arrow and choose All, then
choose Geodatabase from the second dropdown arrow. Click Class Extension under Base Component and click Next.
The ESRI GeoObject Class Extensions component category appears. See the following screen shot:
http://help.arcgis.com/en/sdk/10.0/arcobjects_net/conceptualhelp/index.html#//000100000201000000 5/36
11/6/2015 Creating class extensions
4. Select the ESRI GeoObject Class Extensions check box and click Next. A list of available optional interfaces appear,
which is only a subset of the optional interfaces. Despite being termed optional, always choose IObjectClassExtension
from this list and if the class extension applies to feature classes, also choose IFeatureClassExtension. Choose any
other interfaces to implement and click Finish. See the following screen shot:
http://help.arcgis.com/en/sdk/10.0/arcobjects_net/conceptualhelp/index.html#//000100000201000000 6/36
11/6/2015 Creating class extensions
Create a class extension in a class library that is registered for COM interop. To ensure a class library is registered for COM
interop, in Visual Studio rightclick the project and click Properties. Select the COM interop check box near the bottom of the
Build page.
Applying a class extension
There are several ways to apply an extension to a class, depending on whether the class already exists and whether the
extension is applied through an application or programmatically. Two options exist to apply an extension to new object classes—
creating description classes and passing the class extension's GUID as a parameter of the IFeatureWorkspace.CreateTable and
CreateFeatureClass methods. For existing object classes, class extensions can be applied through the IClassSchemaEdit and
IFeatureWorkspaceSchemaEdit interfaces.
Classes can have a maximum of one associated extension.
Creating and registering description classes for an extension has the benefit of allowing ArcCatalog to "find" the new class
extension and letting users create classes with the extension through that application. For more information on creating
description classes, see Creating custom class descriptions in this topic.
Passing the class extension's GUID to the IFeatureWorkspace.CreateTable or IFeatureWorkspace.CreateFeatureClass methods can
http://help.arcgis.com/en/sdk/10.0/arcobjects_net/conceptualhelp/index.html#//000100000201000000 7/36
11/6/2015 Creating class extensions
be quicker during testing and debugging of the class extension, but in most cases, even custom clients benefit from the
implementation of an object class description.
To apply an extension to an existing class, obtain an exclusive schema lock, then call the
IClassSchemaEdit.AlterClassExtensionCLSID method. This method can also be used to remove a class extension by providing null
values as both parameters. See the following code example:
[C#]
public void ChangeClassExtension(IObjectClass objectClass, String extensionUID,
IPropertySet extensionProperties)
{
ISchemaLock schemaLock = (ISchemaLock)objectClass;
try
{
// Attempt to get an exclusive schema lock.
schemaLock.ChangeSchemaLock(esriSchemaLock.esriExclusiveSchemaLock);
if (!String.IsNullOrEmpty(extensionUID))
{
// Create a unique identifier (UID) object and change the extension.
UID extUID = new UIDClass();
extUID.Value = extensionUID;
classSchemaEdit.AlterClassExtensionCLSID(extUID, extensionProperties);
}
else
{
// Clear the class extension.
classSchemaEdit.AlterClassExtensionCLSID(null, null);
}
}
catch (COMException comExc)
{
throw new Exception("Could not change class extension.", comExc);
}
finally
{
schemaLock.ChangeSchemaLock(esriSchemaLock.esriSharedSchemaLock);
}
}
[VB.NET]
Public Sub ChangeClassExtension(ByVal objectClass As IObjectClass, ByVal extensionUID As String, ByVal extensionProperties As IPropertySet)
Dim schemaLock As ISchemaLock = CType(objectClass, ISchemaLock)
Try
' Attempt to get an exclusive schema lock.
schemaLock.ChangeSchemaLock(esriSchemaLock.esriExclusiveSchemaLock)
' Cast the object class to the IClassSchemaEdit2 interface.
http://help.arcgis.com/en/sdk/10.0/arcobjects_net/conceptualhelp/index.html#//000100000201000000 8/36
11/6/2015 Creating class extensions
' Cast the object class to the IClassSchemaEdit2 interface.
Dim classSchemaEdit As IClassSchemaEdit = CType(objectClass, IClassSchemaEdit)
If Not String.IsNullOrEmpty(extensionUID) Then
' Create a unique identifier (UID) object and change the extension.
Dim extUID As UID = New UIDClass()
extUID.Value = extensionUID
classSchemaEdit.AlterClassExtensionCLSID(extUID, extensionProperties)
Else
' Clear the class extension.
classSchemaEdit.AlterClassExtensionCLSID(Nothing, Nothing)
End If
Catch comExc As COMException
Throw New Exception("Could not change class extension.", comExc)
Finally
schemaLock.ChangeSchemaLock(esriSchemaLock.esriSharedSchemaLock)
End Try
End Sub
If an extension is faulty or has not been properly installed on the client machine, opening the class might not be possible. If
this occurs, the workspace can be cast to the IFeatureWorkspaceSchemaEdit interface and the AlterClassExtensionCLSID method
of that interface can be called to remove the extension.
Implementing interfaces
Class extensions should implement, at a minimum, two interfaces—IClassExtension and IObjectClassExtension. If the extension
is being designed for feature classes, also implement the IFeatureClassExtension interface. IClassExtension is the only required
interface, but IObjectClassExtension and IFeatureClassExtension are indicator interfaces and implementing them will not increase
development time.
Event handling within a class extension is slightly different from applicationlevel event handlers, such as custom event
listeners. Rather than explicitly "wiring" event handling methods to the source of the events, class extensions automatically
receive events by implementing their optional event interfaces, such as IObjectClassEvents. Custom objects can also define
event handlers for this interface. For more information, see Listening to object class events.
Numerous optional interfaces exist for object class and feature class extensions, which includes the following:
IObjectClassValidation
IObjectClassEvents
IObjectClassInfo and IObjectClassInfo2
IRelatedObjectClassEvents and IRelatedObjectClassEvents2
IConfirmSendRelatedObjectEvents
IFeatureClassEdit
IFeatureClassDraw (feature class extensions only)
IFeatureClassCreation (feature class extensions only)
Developers should also be aware of the persistence provided by extension properties. Extension properties are keyvalue pairs
stored in the geodatabase and are unique to each class, not the extension, allowing each instance of the extension to maintain
http://help.arcgis.com/en/sdk/10.0/arcobjects_net/conceptualhelp/index.html#//000100000201000000 9/36
11/6/2015 Creating class extensions
its own properties. Extension properties can be read from the geodatabase with the IClass.ExtensionProperties property, and
written to the geodatabase using the IClassSchemaEdit2.AlterClassExtensionProperties method. If the properties are used
frequently by the extension, they can be stored as member variables during extension initialization—they are passed in as a
parameter of the IClassExtension.Init method. This approach minimizes the amount of serialization and geodatabase roundtrips.
Finally, members not specified by any interface (or by a custom interface) can be created in an extension as a way of defining
custom behavior and storing data. This is a common way of modifying extension properties. These members can then be
accessed by custom clients or other ArcGIS customizations, such as editor or workspace extensions, custom commands, or
custom property pages.
It is important to remember that a class extension can be called by any geodatabase client, including ArcMap, ArcCatalog, and
custom clients. Because of this, the extension should never be responsible for output, as both graphical user interface (GUI)
output or console output will be inappropriate for some applications. Writing to the local file system, while useful in some cases,
should be implemented carefully, as not all client machines have a common file structure.
IClassExtension
A class extension must implement IClassExtension. It defines two methods—Init and Shutdown—which are called when the class
extension is initialized and disposed of, respectively. Class extensions are initialized when their associated class is opened or
when they are applied to an existing class. Shutdown is called when their associated class is disposed of or when the extensions
are removed from the class.
Depending on the client, Shutdown might not be called when a class is deleted. This is because Shutdown is called when the
class is freed from memory, which does not necessarily occur when a class is deleted from a geodatabase. If this is the case, it
will be called when the client is closed.
The Init method provides references that can be crucial for other methods to operate correctly. It has two parameters, one of
type IClassHelper and one of type IPropertySet. The class helper is an object that provides a reference to the extension's
associated class, which many extensions require. It is highly recommended that this reference be stored in a member variable
for use by other properties and methods. The property set contains the extension properties, if any exist. If none exist, a null
value is passed into the method. For more information on extension properties, see Working with extension properties in this
topic.
The following code example shows a simple implementation of the Init method:
[C#]
private IClassHelper classHelper = null;
http://help.arcgis.com/en/sdk/10.0/arcobjects_net/conceptualhelp/index.html#//000100000201000000 10/36
11/6/2015 Creating class extensions
[VB.NET]
Private classHelper As IClassHelper = Nothing
Public Sub Init(ByVal classHelper As IClassHelper, ByVal extensionProperties As IPropertySet) Implements IClassExtension.Init
' Store the class helper reference.
Me.classHelper = classHelper
End Sub
Working with extension properties
Extension properties allow a set of objects to be persisted with a class as metadata. These properties can include strings,
images, and other objects. Extension properties are stored on a classbyclass basis, not for the extension as a whole, allowing
each class with the extension to be configured individually.
Extension properties are accessible from the extension's associated class, through the IClass.ExtensionProperties property, and
are passed to the IClassExtension.Init method as a parameter. If the properties are to be used by other methods within the
extension, save the properties in member variables during the Init method. Properties can be modified at any time by casting
the class to the IClassSchemaEdit2 interface and calling the AlterClassExtensionProperties method with a new set of properties
as a parameter. If the properties are to be modified by the extension, a reference to the class can be obtained through the
extension's class helper, which is also passed into the IClassExtension.Init method as a parameter. As with other methods in the
IClassSchemaEdit interfaces, obtain an exclusive schema lock for the class before modifying its extension properties.
When a class with an extension is created, it has no extension properties and the value passed into the IClassExtension.Init
parameter is null. If properties are required for the extension to operate correctly, the Init method can check whether the
incoming property set is null and if so, apply a default set of properties.
The following code example shows an excerpt from an extension that keeps a log file of class activity, by using a default
location unless a property is set to override the default. The LogFile property is a member of a custom interface, accessible by
a property page.
[C#]
private IPropertySet extensionProperties = null;
private IClassHelper classHelper = null;
}
http://help.arcgis.com/en/sdk/10.0/arcobjects_net/conceptualhelp/index.html#//000100000201000000 11/36
11/6/2015 Creating class extensions
}
set
{
// Get the base class and cast to the IClassSchemaEdit2 interface.
IClass baseClass = classHelper.Class;
IClassSchemaEdit2 classSchemaEdit = (IClassSchemaEdit2)baseClass;
[VB.NET]
Private extensionProperties As IPropertySet = Nothing
IObjectClassExtension and IFeatureClassExtension
The IObjectClassExtension and IFeatureClassExtension interfaces do not define any methods or properties, but act as indicator
interfaces (they are used to identify the extension's type). It is recommended that all class extensions implement the
IObjectClassExtension interface and those that have feature class specific functionality implement the IFeatureClassExtension
interface.
IObjectClassEvents
Use the IObjectClassEvents interface to define custom behavior when objects are created, deleted, or modified. These events
occur following the IRow.Store or IRow.Delete methods and before the notification of related or external objects. Because the
events follow Store and Delete calls, Store and Delete should not be called on the object from the extension's implementation.
The following code example shows how to use the OnCreate method to timestamp new objects with their creation date.
Implement OnDelete and OnChange even though in this case, they do not define any functionality.
[C#]
private static readonly String timestampFieldName = "CREATED";
[VB.NET]
Private Const TIMESTAMP_FIELD_NAME As String = "CREATED"
If the OnCreate method is used to define custom behavior, it might be necessary to implement the IObjectClassInfo interface.
For more information, see IObjectClassInfo and IObjectClassInfo2 in this topic.
IObjectClassValidation
The IObjectClassValidation interface is used to implement validation rules that are more complex than outofthebox rules can
accommodate. Examples of this include the following:
Fields with string values that require the use of string functions for validation
Fields with a range of numeric values that must be validated using another field, also with a range of numeric values
(making it unsuitable for subtyping)
Fields with values that are constrained by a combination of multiple fields
Fields with values that must be validated by checking external sources, such as a data dictionary table or the local file
system
The following two methods are defined by IObjectClassValidation:
ValidateRow
http://help.arcgis.com/en/sdk/10.0/arcobjects_net/conceptualhelp/index.html#//000100000201000000 14/36
11/6/2015 Creating class extensions
ValidateField
ValidateRow is called after the geodatabase's native validation has been completed. Typically, ValidateRow will be implemented
to call ValidateField on each field requiring custom validation. Both of these methods have string return types. If the validation
is successful, an empty string should be returned; otherwise, a description of the error should be returned.
The following code example shows how to perform regular expression matching as part of custom validation. A simple regular
expression is used to validate email addresses; note that this expression is overly simplified for the example and might not
conform to standards in some cases. It is assumed that any class this would be applied to has a string field named "Email," but
in a production environment, this value would likely be stored as an extension property.
[C#]
// The class extension's class helper.
private IClassHelper classHelper = null;
// A Regex instance created when the class extension is initialized.
private Regex regex = null;
return validationDescription;
}
[VB.NET]
' The class extension's class helper.
Fields are regularly accessed in the methods of several class extension interfaces, such as the
IObjectClassValidation.ValidateField method in the preceding code example and the IObjectClassEvents.OnCreate method in the
next code example. Finding a field's index during a method that can be called repeatedly is strongly discouraged, as doing so
during the bulk validation or creation of objects can negatively affect performance. Instead, determine the field index during the
IClassExtension.Init method and store it in a member variable.
IObjectClassInfo and IObjectClassInfo2
The IObjectClassInfo and IObjectClassInfo2 interfaces provide the following methods that indicate how the data of an object
class should be created and modified:
CanBypassStoreMethod—Indicates if IRow.Store must be called when objects are created in the class
CanBypassEditSession—Indicates if the class requires data modification to take place in an edit session
Although CanBypassStoreMethod and CanBypassEditSession are accessed through the class, if IObjectClassInfo and
IObjectClassInfo2 are implemented by an extension, the class defers its response to that of the extension.
By default, CanBypassStoreMethod returns true for object classes and simple feature classes, and false for feature classes with
complex behavior. Classes with complex behavior often require the Store method to be called, as it triggers the
IObjectClassEvents.OnCreate method. CanBypassStoreMethod is called by insert cursors when objects are added to a class; if it
returns true, Store will not be called by the cursor.
Insert cursors are used throughout ArcGIS Desktop applications, such as in the ArcCatalog Simple Data Loader and in
geoprocessing tools. If a class extension implements the IObjectClassEvents interface and has important functionality in the
OnCreate method, or the class has other listeners of IObjectClassEvents, implement this method and it returns false. The
following code example shows a typical implementation of this method:
[C#]
public Boolean CanBypassStoreMethod()
{
return false;
}
http://help.arcgis.com/en/sdk/10.0/arcobjects_net/conceptualhelp/index.html#//000100000201000000 17/36
11/6/2015 Creating class extensions
[VB.NET]
Public Function CanBypassStoreMethod() As Boolean Implements IObjectClassInfo.CanBypassStoreMethod
Return False
End Function
In addition to cases where custom behavior is defined by a class extension, it might be necessary to implement
CanBypassStoreMethod if an editor extension is listening for events from a specific class. If IRow.Store is not called when an
object is created or modified, geodatabase events will not be passed to the editor extension. For example, this can occur when
using ArcMap's Object Loader, which by default, will not call IRow.Store for simple feature classes. If an editor extension
depends on the reception of these events, the class should be given an extension and the extension's CanBypassStoreMethod
returns false.
Alternatively, the IWorkspaceEditControl interface can be used to specify that Store should be called when editing any class in a
workspace.
The CanBypassEditSession method indicates whether a class requires objects to be created, deleted, or changed outside of an
edit session. Some classes, such as those participating in a network, require an edit session to ensure proper multiuser behavior
and the correct management of objects internally cached database states. If a class extension requires edit events to be handled
(such as those from the IWorkspaceEditEvents interface) to validate or modify classes or private datasets, implement this
method and it returns false. Doing so prevents applications from editing the class outside an edit session. The following code
example is a typical implementation of this method:
[C#]
public Boolean CanBypassEditSession()
{
return false;
}
[VB.NET]
Public Function CanBypassEditSession() As Boolean Implements IObjectClassInfo2.CanBypassEditSession
Return False
End Function
Class policies—whether it requires the Store method or an edit session—can only be tightened by these methods. For example, a
feature class that participates in a topology must be edited in an edit session, and implementing a class extension that returns
true from the CanByPassEditSession method will not change this.
IRelatedObjectClassEvents and IRelatedObjectClassEvents2
Use the IRelatedObjectClassEvents and IRelatedObjectClassEvents2 interfaces to handle editing events from a class that is
related through a relationship class to the extension's class. The former interface defines only a single method,
RelatedObjectCreated, which is called when a new object is created in a related class. The latter defines several more methods,
most notably RelatedObjectChanged, which is called when an object in a related class is modified, as well as four other methods
that are triggered by calls to the IFeatureEdit interface.
http://help.arcgis.com/en/sdk/10.0/arcobjects_net/conceptualhelp/index.html#//000100000201000000 18/36
11/6/2015 Creating class extensions
For any of these methods to be called on a class extension, the proper notification must be enabled in the relationship class. If
the extension is on the origin class, notification must be set to Backward or Both, and if the extension is on the destination
class, notification must be set to Forward or Both.
Unlike many similarly named interfaces, IRelatedObjectClassEvents2 does not inherit from IRelatedObjectClassEvents. For a
class extension to define event handlers for both, it must explicitly implement both.
In most cases, creating a class extension for the source of these events and implementing the IObjectClassEvents interface is
the best way to provide this functionality. The following are two typical scenarios where implementing a class extension that
listens for related object class events is useful:
When the source class already has a class extension applied to it.
When creating a variation of composite relationship behavior. For example, creating a relationship class that will move and
rotate related features, but will not cascade deletion.
The RelatedObjectSetMoved and RelatedObjectSetRotated methods can be implemented if a transformation of the related object's
geometry needs to be reflected in the extension's class. This is particularly useful in a relationship between two feature classes,
for example, a relationship class with a feature class of poles and a feature class of transformers. If a pole is moved or rotated
and one or more transformers are attached to that pole, the transformers should move or rotate with it. This can also be useful
in a relationship between a feature class and an object class, for example, if an object's attributes are derived from a related
feature's geometry.
The following code example shows how to use the IRelatedObjectClassEvents2 interface to create this variation of composite
relationship behavior:
[C#]
public void RelatedObjectSetMoved(IRelationshipClass relationshipClass, ISet
objectsThatNeedToChange, ISet objectsThatChanged, ILine moveVector)
{
// Get the first object to change and cast to the IFeatureEdit interface.
objectsThatNeedToChange.Reset();
IFeatureEdit featureEdit = objectsThatNeedToChange.Next()as IFeatureEdit;
// If it is the correct type of object, move the related objects.
if (featureEdit != null)
{
featureEdit.MoveSet(objectsThatNeedToChange, moveVector);
}
}
http://help.arcgis.com/en/sdk/10.0/arcobjects_net/conceptualhelp/index.html#//000100000201000000 19/36
11/6/2015 Creating class extensions
// If it is the correct type of object, move the related objects.
if (featureEdit != null)
{
featureEdit.RotateSet(objectsThatNeedToChange, origin, angle);
}
}
[VB.NET]
Public Sub RelatedObjectSetMoved(ByVal relationshipClass As IRelationshipClass, _
ByVal objectsThatNeedToChange As ISet, ByVal objectsThatChanged As ISet, _
ByVal moveVector As ILine) Implements IRelatedObjectClassEvents2.RelatedObjectSetMoved
' Get the first object to change and cast to the IFeatureEdit interface.
objectsThatNeedToChange.Reset()
Dim featureEdit As IFeatureEdit = TryCast(objectsThatNeedToChange.Next(), IFeatureEdit)
' If it is the correct type of object, move the related objects.
If Not featureEdit Is Nothing Then
featureEdit.MoveSet(objectsThatNeedToChange, moveVector)
End If
End Sub
The last two methods that must be implemented to honor the interface are RelatedObjectMoved and RelatedObjectRotated. These
methods are currently reserved and should not define any functionality.
If a class with an extension that implements IRelatedObjectClassEvents or IRelatedObjectClassEvents2 is going to participate in
multiple relationship classes, it is recommended that the IConfirmSendRelatedObjectEvents interface be implemented in tandem.
For more information, see IConfirmSendRelatedObjectEvents in this topic.
There might not be a 1:1 relationship between the objects contained by the set parameters of these methods;
therefore, iterating through the set of origin class objects and the set of destination class objects in parallel (and assuming a
relationship exists) is not recommended. For example, if the relationship class has 1:M cardinality, there can be several objects
in the objectsThatNeedToChange set that are related to a single object in the objectsThatChanged set.
These events are triggered from the IFeatureEdit interface, which is called by the ArcMap editor when features or sets of
http://help.arcgis.com/en/sdk/10.0/arcobjects_net/conceptualhelp/index.html#//000100000201000000 20/36
11/6/2015 Creating class extensions
features are moved or rotated, but not when they are reshaped (the RelatedObjectChanged event is called in that case). Also, if
the related object's geometry is modified directly at the geometry level, for example, by using the ITransform2D.Rotate or
ITransform2D.Move methods, these events will not be triggered.
IConfirmSendRelatedObjectEvents
Implement the IConfirmSendRelatedObjectEvents interface to filter notifications received by the extension from any related
classes. It consists of five methods with Boolean return values, each of which corresponds to a method in the
IRelatedObjectClassEvents2 interface. If a class extension implements these and a method returns false, the corresponding
IRelatedObjectClassEvents2 method will not be called, effectively "shortcircuiting" the notification.
Despite the name of the interface and methods, apply extensions that implement this interface, not to the source of the
notifications but the receiver. This can be thought of as confirming the reception of a notification rather than the transmission.
A common situation where this interface can be implemented is when change notifications should only be handled if a specific
field of an object is changed (that is, the Shape field). By using the IRowChanges or IFeatureChanges interface, these methods
can determine whether the notification is relevant. Another situation where this can be useful is if notification is dependent on
the source object's subtype.
This interface should also be implemented if a class is receiving notifications from multiple related classes and if events are
only relevant from a specific class. This can be done by checking the name of the relationship class when confirmation begins.
If hard coding a relationship class name is not ideal, build a custom property page to save the relationship class name as an
extension property.
The following code example shows how to restrict change notifications to those where a feature's geometry has been modified.
Use this in a feature class extension, as it has no effect in an object class extension.
[C#]
// The name of the ownership relationship class. TODO: This should be set by implementing an
// extension specific method, along with a property page, and stored in the extension properties.
private String ownershipRelClassName = null;
// Cast to the IFeatureChanges interface and check for shape change.
IFeatureChanges featureChanges = objectThatChanged as IFeatureChanges;
if (featureChanges != null)
{
return featureChanges.ShapeChanged;
http://help.arcgis.com/en/sdk/10.0/arcobjects_net/conceptualhelp/index.html#//000100000201000000 21/36
11/6/2015 Creating class extensions
return featureChanges.ShapeChanged;
}
[VB.NET]
' The name of the ownership relationship class. TODO: This should be set by implementing an
' extension specific method, along with a property page, and stored in the extension properties.
Private ownershipRelClassName As String = Nothing
IObjectInspector
The Attributes dialog box in ArcMap is used to view and edit an object's attributes during an edit session. It contains a tree
view, which shows the currently selected objects and a list view, which contains the names and values for each field of the
object selected in the tree view. The list view is the default object inspector or feature inspector (the terms are
interchangeable).
See the following screen shot that shows the Attributes dialog box with the default object inspector:
http://help.arcgis.com/en/sdk/10.0/arcobjects_net/conceptualhelp/index.html#//000100000201000000 22/36
11/6/2015 Creating class extensions
The IObjectInspector interface allows the creation of a custom feature inspector as part of a class extension. Custom feature
inspectors can offer a more application specific editing experience, for example, providing calendar controls to edit date values,
displaying raster images, or providing an OpenFileDialog for fields that expect local file names.
A feature inspector should not be used as the primary method of restricting user input, such as using radio buttons or combo
boxes. While these can be applicable to the class's schema, view form level logic as a supplement to domains, subtypes, and
validation rules and not a replacement.
For an example of a class extension that provides a custom feature inspector, see the Tabbed feature inspector sample.
The buttons at the top of the Attributes dialog box—for example, for sorting—will not have any effect when used with a custom
feature inspector.
IFeatureClassEdit
Use the IFeatureClassEdit interface for specifying advanced editing configuration for a feature class or object class (has two
properties, CanEditWithProjection and CustomSplitPolicyForRelationship, and one method, HasCustomSplitPolicyForRelationship).
http://help.arcgis.com/en/sdk/10.0/arcobjects_net/conceptualhelp/index.html#//000100000201000000 23/36
11/6/2015 Creating class extensions
ArcMap supports the editing of simple features in a different spatial reference than that of the feature class. If the associated
feature class contains simple features, editing of the feature class in a different spatial reference can be prevented by
implementing the CanEditWithProjectionproperty and returning false. See the following code example for a typical
implementation:
[C#]
public Boolean CanEditWithProjection
{
get
{
return false;
}
}
[VB.NET]
Public ReadOnly Property CanEditWithProjection() As Boolean Implements IFeatureClassEdit.CanEditWithProjection
Get
Return False
End Get
End Property
When a feature with related objects is split, the geodatabase can delete the related objects, create relationships, or only
maintain the relationships with the larger portion of the split feature, depending on the type and cardinality of the relationship
class. If the default split policy is not the desired behavior, return true from HasCustomSplitPolicy. The
CustomSplitPolicyForRelationship property can then be used to specify a custom split policy according to the relationship class
and properties, such as subtype, of the feature being split. If this interface is implemented solely for the CanEditWithProjection
property, false is returned (and the split policy property can return anything, as it will not be called).
An example of when this would be useful is with a relationship class between parcels and owners. If the relationship class is
simple and has 1:M cardinality, when a parcel is divided, the owner remains related to the larger of the two new parcels, but
the smaller will not have an owner. The following code example shows how to modify this behavior so that both parts of the
parcel remains related to the owner:
[C#]
// Load from extension properties in IClassExtension.Init.
private String parcelOwnerRelClassName = null;
[VB.NET]
Public Function HasCustomSplitPolicyForRelationship() As Boolean Implements IFeatureClassEdit.HasCustomSplitPolicyForRelationship
Return True
End Function
An extension that uses this interface to define a custom split policy can be applied to the source or destination class of the
relationship class. Although the CanEditWithProjection property is only applicable to feature class extensions, the ability to define
a custom split policy also makes this interface relevant to object class extensions.
IFeatureClassDraw
Use the IFeatureClassDraw interface to specify custom drawing behavior for a feature class. Custom drawing can be achieved
with a custom renderer or by creating custom features that implement the IFeatureDraw interface. Only implement this interface
in a feature class extension.
ArcGIS applications with threedimensional (3D) rendering (that is, ArcGlobe, ArcScene, and ArcGIS Explorer) might not honor
http://help.arcgis.com/en/sdk/10.0/arcobjects_net/conceptualhelp/index.html#//000100000201000000 25/36
11/6/2015 Creating class extensions
[VB.NET]
Public Function DoesCustomDrawing() As Boolean Implements IFeatureClassDraw.DoesCustomDrawing
Return True
End Function
The HasCustomRenderer method and ExclusiveCustomRenderer property have Boolean return types and are also easy to
implement.
HasCustomRenderer returns true if the custom drawing behavior is implemented with a custom renderer and returns false
if the behavior is defined in a custom feature.
ExclusiveCustomRenderer returns true if the custom renderer is the only renderer that layers can use when the feature
class displays (false allows others to be used).
If an exclusive custom renderer is defined but the specified renderer is not available to a client, the client uses the default
renderer (in ArcMap, the Single Symbol renderer). The following is a typical code example:
[C#]
public Boolean ExclusiveCustomRenderer
{
get
{
return false;
}
}
[VB.NET]
Public ReadOnly Property ExclusiveCustomRenderer() As Boolean Implements IFeatureClassDraw.ExclusiveCustomRenderer
Get
Return True
End Get
End Property
It is recommended that a feature class extension defining a custom drawing be applied before the feature class is included in
ArcMap documents or layer files. If these files include the feature class before the application of an extension that defines a
custom renderer as exclusive, these files will not honor the extension's specifications.
CustomRenderer and CustomRendererPropPageCLSID define the renderer used. CustomRenderer returns an instance of the
renderer associated with the class and CustomRendererPropPageCLSID returns a unique identifier (UID) instance for the
renderer's property page. If the custom drawing is implemented through a custom feature and not a custom renderer, null can
be returned. See the following code example:
[C#]
public object CustomRenderer
{
get
{
Type type = Type.GetTypeFromProgID("PointDispersal.Renderer");
return Activator.CreateInstance(type);
}
}
[VB.NET]
Public ReadOnly Property CustomRenderer() As Object Implements IFeatureClassDraw.CustomRenderer
Get
Dim Type As Type = Type.GetTypeFromProgID("PointDispersal.Renderer")
Return Activator.CreateInstance(Type)
End Get
End Property
http://help.arcgis.com/en/sdk/10.0/arcobjects_net/conceptualhelp/index.html#//000100000201000000 27/36
11/6/2015 Creating class extensions
End Property
The final property is only important if custom drawing is implemented through custom features. RequiredFieldsForDraw
specifies the fields' (other than the Shape field) features required in their implementation of IFeatureDraw.Draw. By default, the
feature cursor used in the drawing process only retrieves the features' geometries. If others are required, they should be
returned as a fields collection by this property. The following code example is suitable in a scenario where the ObjectID (OID)
field is used by the custom feature:
[C#]
public IFields RequiredFieldsForDraw
{
get
{
// Get the class's OID field.
IClass baseClass = classHelper.Class;
String oidFieldName = baseClass.OIDFieldName;
int oidFieldIndex = baseClass.FindField(oidFieldName);
IFields baseClassFields = baseClass.Fields;
IField oidField = baseClassFields.get_Field(oidFieldIndex);
return fields;
}
}
[VB.NET]
Public ReadOnly Property RequiredFieldsForDraw() As IFields Implements IFeatureClassDraw.RequiredFieldsForDraw
Get
' Get the class's OID field.
Dim baseClass As IClass = classHelper.Class
Dim oidFieldName As String = baseClass.OIDFieldName
Dim oidFieldIndex As Integer = baseClass.FindField(oidFieldName)
Dim baseClassFields As IFields = baseClass.Fields
Dim oidField As IField = baseClassFields.Field(oidFieldIndex)
http://help.arcgis.com/en/sdk/10.0/arcobjects_net/conceptualhelp/index.html#//000100000201000000 28/36
11/6/2015 Creating class extensions
Return fields
End Get
End Property
Creating custom class descriptions
Class descriptions provide applications and developers with a template for dataset creation. Two frequently used examples of
this are object class descriptions and feature class descriptions, both included with ArcGIS. ArcCatalog uses these to determine
the required fields of a new object or feature class, and their instance of class identifiers (CLSIDs) and extension CLSIDs.
ArcGIS also includes other class descriptions for classes, such as annotation, dimensions, and raster catalogs. Creating a feature
class description makes a new type of feature class visible to ArcGIS and both object and feature class descriptions are
convenient ways for developers to access information about the class.
If the new class type contains nonspatial data, the description class should implement the IObjectClassDescription interface and
if it contains features, it should also implement the IFeatureClassDescription interface. Like a class extension, a class description
requires component category registration but should be registered to the GeoObjectClassDescriptions category rather than the
GeoObjectClassExtensions category.
The name properties of a class description are easy to implement. The following are the name properties that are required for a
description:
Name—Returns what users see in the Type section of the ArcCatalog New Feature Class dialog box when creating a new
feature class
AliasName—Provides an alternate name for the object class description
ModelName—Provides an additional way of guaranteeing a class is unique
In most cases, the AliasName and ModelName properties are unused and it is safe to return empty strings. In addition to the
three previously mentioned properties, the ModelNameUnique property indicates if the model name is unique. If a blank model
name is used, false is returned.
The following code example shows a typical implementation of the Name, AliasName, ModelName, and ModelNameUnique
properties:
[C#]
public String Name
{
get
{
return "Timestamped Class";
}
}
[VB.NET]
Public ReadOnly Property Name() As String Implements IObjectClassDescription.Name
Get
Return "Timestamped Class"
End Get
End Property
The InstanceCLSID and ClassExtensionCLSID properties return UID instances containing the GUIDs of the classes' objects (or
features) and of the classes' extension, respectively. Many classes return UIDs containing the GUIDs of the object or feature
class, but classes designed to use custom features return a UID containing the value of the custom feature's GUID. The
ClassExtensionCLSID property returns a UID containing the appropriate class extension's GUID. The following code example
shows a typical implementation of these two properties:
[C#]
public UID InstanceCLSID
{
get
{
[VB.NET]
Public ReadOnly Property InstanceCLSID() As UID Implements IObjectClassDescription.InstanceCLSID
Get
Dim uid As UID = New UIDClass()
uid.Value = "{52353152‐891A‐11D0‐BEC6‐00805F7C4268}"
Return uid
End Get
End Property
RequiredFields returns a fields collection containing the required fields for the description's class type to operate properly. For
example, an object class description returns a fields collection containing one ObjectID field, whereas a feature class description
returns an ObjectID field and a Shape field. The following code example shows an implementation of this property for a time
stamped class, which requires "Created" and "Modified" date fields:
[C#]
public IFields RequiredFields
{
get
{
// Get the feature class required fields.
IFeatureClassDescription fcDescription = new FeatureClassDescriptionClass();
IObjectClassDescription ocDescription = (IObjectClassDescription)
fcDescription;
IFields requiredFields = ocDescription.RequiredFields;
IFieldsEdit requiredFieldsEdit = (IFieldsEdit)requiredFields;
return requiredFields;
}
}
[VB.NET]
Public ReadOnly Property RequiredFields() As IFields Implements IObjectClassDescription.RequiredFields
Get
' Get the feature class required fields.
Dim fcDescription As IFeatureClassDescription = New FeatureClassDescriptionClass()
Dim ocDescription As IObjectClassDescription = CType(fcDescription, IObjectClassDescription)
Dim fields As IFields = ocDescription.RequiredFields
Dim fieldsEdit As IFieldsEdit = CType(fields, IFieldsEdit)
Return fields
End Get
End Property
If the class description is for a feature class, the following properties are also required by the IFeatureClassDescription
interface:
http://help.arcgis.com/en/sdk/10.0/arcobjects_net/conceptualhelp/index.html#//000100000201000000 32/36
11/6/2015 Creating class extensions
FeatureType—Returns the feature type to be created (that is, simple, simple junction, or simple edge)
ShapeFieldName—Returns the default Shape field name (by default, SHAPE for feature classes)
The following code example shows a typical implementation of these properties:
[C#]
public esriFeatureType FeatureType
{
get
{
return esriFeatureType.esriFTSimple;
}
}
[VB.NET]
Public ReadOnly Property FeatureType() As esriFeatureType Implements IFeatureClassDescription.FeatureType
Get
Return esriFeatureType.esriFTSimple
End Get
End Property
When a feature class description is implemented and registered in the appropriate component category, it can be created in
ArcCatalog. See the following screen shot:
http://help.arcgis.com/en/sdk/10.0/arcobjects_net/conceptualhelp/index.html#//000100000201000000 33/36
11/6/2015 Creating class extensions
In addition to availability in ArcCatalog, having a class description also makes a developer's job easier, as descriptions are a
convenient way to get UIDs and required fields in a custom client. See the following code example:
[C#]
// Create an instance of the TimestampedClassDescription.
Type tsDescriptionType = Type.GetTypeFromProgID(
http://help.arcgis.com/en/sdk/10.0/arcobjects_net/conceptualhelp/index.html#//000100000201000000 34/36
11/6/2015 Creating class extensions
Type tsDescriptionType = Type.GetTypeFromProgID(
"TimestampedClassDescription.TimestampedClassDescription");
object tsDescriptionObject = Activator.CreateInstance(tsDescriptionType);
// Cast the description object to ArcGIS class description interfaces.
IFeatureClassDescription fcDescription = (IFeatureClassDescription)
tsDescriptionObject;
IObjectClassDescription ocDescription = (IObjectClassDescription)tsDescriptionObject;
[VB.NET]
' Create an instance of the TimestampedClassDescription.
Dim tsDescriptionType As Type = Type.GetTypeFromProgID("TimestampedClassDescription.TimestampedClassDescription")
Dim tsDescriptionObject As Object = Activator.CreateInstance(tsDescriptionType)
' Cast the description object to ArcGIS class description interfaces.
Dim fcDescription As IFeatureClassDescription = CType(tsDescriptionObject, IFeatureClassDescription)
Dim ocDescription As IObjectClassDescription = CType(tsDescriptionObject, IObjectClassDescription)
See Also:
Geodatabase extensions
Creating workspace extensions
How to register COM components
Listening to object class events
To use the code in this topic, reference the following assemblies in your Visual Studio project. In the code files, you will need
using (C#) or Imports (VB .NET) directives for the corresponding namespaces (given in parenthesis below if different from the
assembly name):
ESRI.ArcGIS.ADF.Local
ESRI.ArcGIS.System (ESRI.ArcGIS.esriSystem)
ESRI.ArcGIS.Geodatabase
ESRI.ArcGIS.Geometry
http://help.arcgis.com/en/sdk/10.0/arcobjects_net/conceptualhelp/index.html#//000100000201000000 35/36
11/6/2015 Creating class extensions
Development licensing Deployment licensing
ArcView ArcView
ArcEditor ArcEditor
ArcInfo ArcInfo
Engine Developer Kit Engine Runtime: Geodatabase Update
http://help.arcgis.com/en/sdk/10.0/arcobjects_net/conceptualhelp/index.html#//000100000201000000 36/36