In this topic
Implementing merge geometries within a version event
If the same feature is modified in two different versions, the shape attribute for that feature will always be in conflict. This makes logical sense because the binary shape object will have changed on each version. In the event of a reconcile between the two versions, the geometry change can be resolved in favor of either version, but this means that the shape changes on one of the versions will be lost. Even though these types of conflicts are valid, for many workflows it is not always desirable to have UpdateUpdate conflicts on the shape attribute.
For example, take the scenario of two editors editing in their own version to modify the same coastline polygon feature. If the first editor modified a section of coastline and another editor modified the same feature in a completely spatially unrelated section of the coastline, both changes are technically valid. However, it is possible to merge conflicting geometries when a conflict arises on the shape field. Merging both geometries attempts to create one geometry, which is the result of a merge between two other geometries. The merging geometries functionality can be leveraged through the use of the IConstructMerge interface in the Geometry library.
Listening to the versioned event
Do the following to listen to the versioned event:
- If the goal is to merge any conflicting edits to the shape field, subscribe to the OnConflictsDetected event.
- This event is raised when conflicts are detected on a reconcile between versions and allows the application developer to make changes to the version based on the results of the reconcile. For more information on listening to versioned events, see Listening to versioned events.
See the following code example—the constructor of a custom listener class—that subscribes to the OnConflictsDetected event:
public MergeEventListener(IVersion version)
{
// Save the version as a member variable.
featureWorkspace = (IFeatureWorkspace)version;
// Subscribe to the OnReconcile event.
IVersionEvents_Event versionEvent = (IVersionEvents_Event)version;
versionEvent.OnConflictsDetected += new
IVersionEvents_OnConflictsDetectedEventHandler(OnConflictsDetected);
}
public void OnConflictsDetected(ref bool conflictsRemoved, ref bool errorOccurred,
ref string errorString)
{
// TODO: Implement custom behavior.
}
[VB.NET]
Public Sub New(ByVal Version As IVersion)
' Save the version as a member variable.
featureWorkspace = CType(Version, IFeatureWorkspace)
' Subscribe to the OnReconcile event.
Dim versionEvent As IVersionEvents_Event = CType(Version, IVersionEvents_Event)
AddHandler versionEvent.OnConflictsDetected, AddressOf OnConflictsDetected
End Sub
Public Sub OnConflictsDetected(ByRef conflictsRemoved As Boolean, ByRef errorOccurred As Boolean, _
ByRef errorString As String)
' TODO: Implement custom behavior.
End Sub
Getting the classes in conflict
Do the following to get the classes in conflict:
- After a handler has subscribed to the OnConflictsDetected event, it is possible to implement custom code to execute when conflicts are detected. In this case, the IVersionEdit.ConflictClasses method is leveraged to get an enumeration of all the classes with conflicts.
- Looping through each conflicting class, request the IConflictClass interface for a selection set of all the UpdateUpdate conflicts found on the class.
See the following code example:
IVersionEdit4 versionEdit4 = (IVersionEdit4)featureWorkspace;
// Get the various versions on which to output information.
IFeatureWorkspace commonAncestorFWorkspace = (IFeatureWorkspace)
versionEdit4.CommonAncestorVersion;
IFeatureWorkspace preReconcileFWorkspace = (IFeatureWorkspace)
versionEdit4.PreReconcileVersion;
IFeatureWorkspace reconcileFWorkspace = (IFeatureWorkspace)
versionEdit4.ReconcileVersion;
IEnumConflictClass enumConflictClass = versionEdit4.ConflictClasses;
IConflictClass conflictClass = null;
while ((conflictClass = enumConflictClass.Next()) != null)
{
IDataset dataset = (IDataset)conflictClass;
// Make sure the class is a feature class.
if (dataset.Type == esriDatasetType.esriDTFeatureClass)
{
String datasetName = dataset.Name;
IFeatureClass featureClass = featureWorkspace.OpenFeatureClass(datasetName);
Console.WriteLine("Conflicts on feature class {0}", datasetName);
// Get all UpdateUpdate conflicts.
ISelectionSet updateUpdates = conflictClass.UpdateUpdates;
[VB.NET]
Dim versionEdit4 As IVersionEdit4 = CType(featureWorkspace, IVersionEdit4)
' Get the various versions on which to output information.
Dim commonAncestorFWorkspace As IFeatureWorkspace = CType(versionEdit4.CommonAncestorVersion, IFeatureWorkspace)
Dim preReconcileFWorkspace As IFeatureWorkspace = CType(versionEdit4.PreReconcileVersion, IFeatureWorkspace)
Dim reconcileFWorkspace As IFeatureWorkspace = CType(versionEdit4.ReconcileVersion, IFeatureWorkspace)
Dim enumConflictClass As IEnumConflictClass = versionEdit4.ConflictClasses
Dim conflictClass As IConflictClass = enumConflictClass.Next()
Do While Not conflictClass Is Nothing
Dim dataset As IDataset = CType(conflictClass, IDataset)
' Make sure the class is a feature class.
If (dataset.Type = esriDatasetType.esriDTFeatureClass) Then
Dim datasetName As String = dataset.Name
Dim featureClass As IFeatureClass = featureWorkspace.OpenFeatureClass(datasetName)
Console.WriteLine("Conflicts on feature class {0}", datasetName)
' Get all UpdateUpdate conflicts.
Dim updateUpdates As ISelectionSet = conflictClass.UpdateUpdates
Determining if the shape is in conflict
Do the following to determine if the shape is in conflict:
- For every conflicting feature on a conflicting class, it is necessary to determine if the Shape column is in conflict. The IConflictClass interface returns references to the different versions used during a reconcile.
See the following code example that gets a reference to the conflict feature on each of the reconcile versions:
if (updateUpdates.Count > 0)
{
// Get conflict feature classes on the three reconcile versions.
IFeatureClass featureClassPreReconcile = preReconcileFWorkspace.OpenFeatureClass
(datasetName);
IFeatureClass featureClassReconcile = reconcileFWorkspace.OpenFeatureClass
(datasetName);
IFeatureClass featureClassCommonAncestor =
commonAncestorFWorkspace.OpenFeatureClass(datasetName);
// Iterate through each OID, outputting information.
IEnumIDs enumIDs = updateUpdates.IDs;
int oid = - 1;
while ((oid = enumIDs.Next()) != - 1)
//Loop through all conflicting features.
{
Console.WriteLine("UpdateUpdate conflicts on feature {0}", oid);
// Get conflict feature on the three reconcile versions.
IFeature featurePreReconcile = featureClassPreReconcile.GetFeature(oid);
IFeature featureReconcile = featureClassReconcile.GetFeature(oid);
IFeature featureCommonAncestor = featureClassCommonAncestor.GetFeature(oid);
[VB.NET]
If (updateUpdates.Count > 0) Then
' Get conflict feature classes on the three reconcile versions.
Dim featureClassPreReconcile As IFeatureClass = preReconcileFWorkspace.OpenFeatureClass(datasetName)
Dim featureClassReconcile As IFeatureClass = reconcileFWorkspace.OpenFeatureClass(datasetName)
Dim featureClassCommonAncestor As IFeatureClass = commonAncestorFWorkspace.OpenFeatureClass(datasetName)
' Iterate through each OID, outputting information.
Dim enumIDs As IEnumIDs = updateUpdates.IDs
Dim oid As Integer = enumIDs.Next()
Do While Not oid = -1 ' Loop through all conflicting features.
Console.WriteLine("UpdateUpdate conflicts on feature {0}", oid)
' Get conflict feature on the three reconcile versions.
Dim featurePreReconcile As IFeature = featureClassPreReconcile.GetFeature(oid)
Dim featureReconcile As IFeature = featureClassReconcile.GetFeature(oid)
Dim featureCommonAncestor As IFeature = featureClassCommonAncestor.GetFeature(oid)
- Comparing the shape attribute on these different versions is necessary to determine if the Shape column is in conflict. When comparing shape attributes, use the IClone interface. Since the IGeometry interface supports IClone, the IClone.IsEqual method is a quick and simple way of determining equivalency between two different geometries.
See the following code example:
// Method to determine if the shape field is in conflict.
private bool IsShapeInConflict(IFeature commonAncestorFeature, IFeature
preReconcileFeature, IFeature reconcileFeature)
{
// 1st check: Common Ancestor with PreReconcile.
// 2nd check: Common Ancestor with Reconcile.
// 3rd check: Reconcile with PreReconcile (case of same change on both versions).
if (IsGeometryEqual(commonAncestorFeature.ShapeCopy,
preReconcileFeature.ShapeCopy) || IsGeometryEqual
(commonAncestorFeature.ShapeCopy, reconcileFeature.ShapeCopy) ||
IsGeometryEqual(reconcileFeature.ShapeCopy, preReconcileFeature.ShapeCopy))
{
return false;
}
else
{
return true;
}
}
// Method returning if two shapes are equal to one another.
private bool IsGeometryEqual(IGeometry shape1, IGeometry shape2)
{
if (shape1 == null & shape2 == null)
{
return true;
}
else if (shape1 == null ^ shape2 == null)
{
return false;
}
else
{
IClone clone1 = (IClone)shape1;
IClone clone2 = (IClone)shape2;
return clone1.IsEqual(clone2);
}
}
[VB.NET]
' Method to determine if the shape field is in conflict.
Private Function IsShapeInConflict(ByVal commonAncestorFeature As IFeature, ByVal preReconcileFeature As IFeature, _
ByVal reconcileFeature As IFeature) As Boolean
' 1st check: Common Ancestor with PreReconcile.
' 2nd check: Common Ancestor with Reconcile.
' 3rd check: Reconcile with PreReconcile (case of same change on both versions).
If IsGeometryEqual(commonAncestorFeature.ShapeCopy, preReconcileFeature.ShapeCopy) Or _
IsGeometryEqual(commonAncestorFeature.ShapeCopy, reconcileFeature.ShapeCopy) Or _
IsGeometryEqual(reconcileFeature.ShapeCopy, preReconcileFeature.ShapeCopy) Then
Return False
Else
Return True
End If
End Function
' Method returning if two shapes are equal to one another.
Private Function IsGeometryEqual(ByVal shape1 As IGeometry, ByVal shape2 As IGeometry) As Boolean
If shape1 Is Nothing And shape2 Is Nothing Then
Return True
ElseIf shape1 Is Nothing Xor shape2 Is Nothing Then
Return False
Else
Dim clone1 As IClone = CType(shape1, IClone)
Dim clone2 As IClone = CType(shape2, IClone)
Return clone1.IsEqual(clone2)
End If
End Function
Merging the conflicting geometries
Do the following to merge the conflicting geometries:
- When the geometries are in conflict, an attempt can be made to merge the geometries using the IConstructMerge interface. There are scenarios where the merge fails; therefore, handling any errors that MergeGeometries can produce is necessary.
- On a successful merge, set the resulting geometry to the current shape object and the result is a new shape incorporating the shape changes on both versions.
See the following code example:
// Check to make sure each shape is different than the common ancestor (conflict is on shape field).
if (IsShapeInConflict(featureCommonAncestor, featurePreReconcile, featureReconcile))
{
Console.WriteLine(" Shape attribute has changed on both versions...");
// Geometries are in conflict ... merge geometries.
try
{
IConstructMerge constructMerge = new GeometryEnvironmentClass();
IGeometry newGeometry = constructMerge.MergeGeometries
(featureCommonAncestor.ShapeCopy, featureReconcile.ShapeCopy,
featurePreReconcile.ShapeCopy);
//Setting new geometry as a merge between the two versions.
IFeature feature = featureClass.GetFeature(oid);
feature.Shape = newGeometry;
feature.Store();
updateUpdates.RemoveList(1, ref oid);
conflictsRemoved = true;
}
catch (COMException comExc)
{
// Check if the error is from overlapping edits.
if (comExc.ErrorCode == (int)
esriGeometryError.E_GEOMETRY_EDITED_REGIONS_OVERLAP)
{
// Edited areas overlap.
Console.WriteLine("Error from overlapping edits on feature {0}", oid);
Console.WriteLine(" Error Message: {0}", comExc.Message);
Console.WriteLine(" Can't merge overlapping edits to same feature.");
}
else
{
// Unexpected COM exception, throw this to the exception handler.
throw comExc;
}
}
}
else
{
Console.WriteLine(" Shape field not in conflict: merge not necessary ... ");
}
[VB.NET]
' Check to make sure each shape is different than the common ancestor (conflict is on shape field).
If IsShapeInConflict(featureCommonAncestor, featurePreReconcile, featureReconcile) Then
Console.WriteLine(" Shape attribute has changed on both versions...")
' Geometries are in conflict ... merge geometries.
Try
Dim constructMerge As IConstructMerge = New GeometryEnvironmentClass()
Dim newGeometry As IGeometry = constructMerge.MergeGeometries(featureCommonAncestor.ShapeCopy, featureReconcile.ShapeCopy, featurePreReconcile.ShapeCopy)
' Setting new geometry as a merge between the two versions.
Dim feature As IFeature = featureClass.GetFeature(oid)
feature.Shape = newGeometry
feature.Store()
updateUpdates.RemoveList(1, oid)
conflictsRemoved = True
Catch comExc As COMException
' Check if the error is from overlapping edits.
If comExc.ErrorCode = fdoError.FDO_E_WORKSPACE_EXTENSION_DATASET_CREATE_FAILED Or _
comExc.ErrorCode = fdoError.FDO_E_WORKSPACE_EXTENSION_DATASET_DELETE_FAILED Then
' Edited areas overlap.
Console.WriteLine("Error from overlapping edits on feature {0}", oid)
Console.WriteLine(" Error Message: {0}", comExc.Message)
Console.WriteLine(" Can't merge overlapping edits to same feature.")
Else
' Unexpected COM exception, throw this to the exception handler.
Throw comExc
End If
End Try
Else
Console.WriteLine(" Shape field not in conflict: merge not necessary ... ")
End If
Removing the feature from the conflict set
Do the following to remove the conflict from the conflict class:
- Call the Remove method to remove the specific feature from the UpdateUpdate conflict set.
- When removing objects from the conflict set, set the conflictsRemoved property on the event to true so the conflicts sets are consistent with the changes made within the event.
See the following code example:
updateUpdates.RemoveList(1, ref oid);
conflictsRemoved = true;
[VB.NET]
updateUpdates.RemoveList(1, oid)
conflictsRemoved = True
Complete code example
By iterating through the ObjectIDs from each conflict class, the code attempts to merge any conflicting geometries, and removes the feature from the UpdateUpdate conflict set if successful.
See the following complete code example:
[C#]
public class MergeEventListener
{
private IFeatureWorkspace featureWorkspace = null;
public MergeEventListener(IVersion version)
{
// Save the version as a member variable.
featureWorkspace = (IFeatureWorkspace)version;
// Subscribe to the OnReconcile event.
IVersionEvents_Event versionEvent = (IVersionEvents_Event)version;
versionEvent.OnConflictsDetected += new
IVersionEvents_OnConflictsDetectedEventHandler(OnConflictsDetected);
}
/// <summary>
/// Pseudocode:
/// - Loop through all conflict classes after the reconcile.
/// - Loop through every UpdateUpdate conflict on the class.
/// - Determine if geometry is in conflict on the feature.
/// - If so, merge geometries together (handling errors) and store the feature.
/// </summary>
public void OnConflictsDetected(ref bool conflictsRemoved, ref bool
errorOccurred, ref string errorString)
{
try
{
IVersionEdit4 versionEdit4 = (IVersionEdit4)featureWorkspace;
// Get the various versions on which to output information.
IFeatureWorkspace commonAncestorFWorkspace = (IFeatureWorkspace)
versionEdit4.CommonAncestorVersion;
IFeatureWorkspace preReconcileFWorkspace = (IFeatureWorkspace)
versionEdit4.PreReconcileVersion;
IFeatureWorkspace reconcileFWorkspace = (IFeatureWorkspace)
versionEdit4.ReconcileVersion;
IEnumConflictClass enumConflictClass = versionEdit4.ConflictClasses;
IConflictClass conflictClass = null;
while ((conflictClass = enumConflictClass.Next()) != null)
{
IDataset dataset = (IDataset)conflictClass;
// Make sure the class is a feature class.
if (dataset.Type == esriDatasetType.esriDTFeatureClass)
{
String datasetName = dataset.Name;
IFeatureClass featureClass = featureWorkspace.OpenFeatureClass
(datasetName);
Console.WriteLine("Conflicts on feature class {0}", datasetName);
// Get all UpdateUpdate conflicts.
ISelectionSet updateUpdates = conflictClass.UpdateUpdates;
if (updateUpdates.Count > 0)
{
// Get conflict feature classes on the three reconcile versions.
IFeatureClass featureClassPreReconcile =
preReconcileFWorkspace.OpenFeatureClass(datasetName);
IFeatureClass featureClassReconcile =
reconcileFWorkspace.OpenFeatureClass(datasetName);
IFeatureClass featureClassCommonAncestor =
commonAncestorFWorkspace.OpenFeatureClass(datasetName);
// Iterate through each OID, outputting information.
IEnumIDs enumIDs = updateUpdates.IDs;
int oid = - 1;
while ((oid = enumIDs.Next()) != - 1)
//Loop through all conflicting features.
{
Console.WriteLine(
"UpdateUpdate conflicts on feature {0}", oid);
// Get conflict feature on the three reconcile versions.
IFeature featurePreReconcile =
featureClassPreReconcile.GetFeature(oid);
IFeature featureReconcile =
featureClassReconcile.GetFeature(oid);
IFeature featureCommonAncestor =
featureClassCommonAncestor.GetFeature(oid);
// Check to make sure each shape is different than the common ancestor (conflict is on shape field).
if (IsShapeInConflict(featureCommonAncestor,
featurePreReconcile, featureReconcile))
{
Console.WriteLine(
" Shape attribute has changed on both versions...");
// Geometries are in conflict ... merge geometries.
try
{
IConstructMerge constructMerge = new
GeometryEnvironmentClass();
IGeometry newGeometry =
constructMerge.MergeGeometries
(featureCommonAncestor.ShapeCopy,
featureReconcile.ShapeCopy,
featurePreReconcile.ShapeCopy);
// Setting new geometry as a merge between the two versions.
IFeature feature = featureClass.GetFeature(oid);
feature.Shape = newGeometry;
feature.Store();
updateUpdates.RemoveList(1, ref oid);
conflictsRemoved = true;
}
catch (COMException comExc)
{
// Check if the error is from overlapping edits.
if (comExc.ErrorCode == (int)
fdoError.FDO_E_WORKSPACE_EXTENSION_DATASET_CREATE_FAILED || comExc.ErrorCode == (int)fdoError.FDO_E_WORKSPACE_EXTENSION_DATASET_DELETE_FAILED)
{
// Edited areas overlap.
Console.WriteLine(
"Error from overlapping edits on feature {0}", oid);
Console.WriteLine(" Error Message: {0}",
comExc.Message);
Console.WriteLine(
" Can't merge overlapping edits to same feature.");
}
else
{
// Unexpected COM exception, throw this to the exception handler.
throw comExc;
}
}
}
else
{
Console.WriteLine(
" Shape field not in conflict: merge not necessary ... ");
}
}
}
}
}
}
catch (COMException comExc)
{
Console.WriteLine("Error Message: {0}, Error Code: {1}", comExc.Message,
comExc.ErrorCode);
}
catch (Exception exc)
{
Console.WriteLine("Unhandled Exception: {0}", exc.Message);
}
}
// Method to determine if the shape field is in conflict.
private bool IsShapeInConflict(IFeature commonAncestorFeature, IFeature
preReconcileFeature, IFeature reconcileFeature)
{
// 1st check: Common Ancestor with PreReconcile.
// 2nd check: Common Ancestor with Reconcile.
// 3rd check: Reconcile with PreReconcile (case of same change on both versions).
if (IsGeometryEqual(commonAncestorFeature.ShapeCopy,
preReconcileFeature.ShapeCopy) || IsGeometryEqual
(commonAncestorFeature.ShapeCopy, reconcileFeature.ShapeCopy) ||
IsGeometryEqual(reconcileFeature.ShapeCopy,
preReconcileFeature.ShapeCopy))
{
return false;
}
else
{
return true;
}
}
// Method returning if two shapes are equal to one another.
private bool IsGeometryEqual(IGeometry shape1, IGeometry shape2)
{
if (shape1 == null & shape2 == null)
{
return true;
}
else if (shape1 == null ^ shape2 == null)
{
return false;
}
else
{
IClone clone1 = (IClone)shape1;
IClone clone2 = (IClone)shape2;
return clone1.IsEqual(clone2);
}
}
}
[VB.NET]
Public Class MergeEventListener
Dim featureWorkspace As IFeatureWorkspace = Nothing
Public Sub New(ByVal Version As IVersion)
' Save the version as a member variable.
featureWorkspace = CType(Version, IFeatureWorkspace)
' Subscribe to the OnReconcile event.
Dim versionEvent As IVersionEvents_Event = CType(Version, IVersionEvents_Event)
AddHandler versionEvent.OnConflictsDetected, AddressOf OnConflictsDetected
End Sub
''' <summary>
''' Pseudocode:
''' - Loop through all conflict classes after the reconcile.
''' - Loop through every UpdateUpdate conflict on the class.
''' - Determine if geometry is in conflict on the feature.
''' - If so, merge geometries together (handling errors) and store the feature.
''' </summary>
Public Sub OnConflictsDetected(ByRef conflictsRemoved As Boolean, ByRef errorOccurred As Boolean, _
ByRef errorString As String)
Try
Dim versionEdit4 As IVersionEdit4 = CType(featureWorkspace, IVersionEdit4)
' Get the various versions on which to output information.
Dim commonAncestorFWorkspace As IFeatureWorkspace = CType(versionEdit4.CommonAncestorVersion, IFeatureWorkspace)
Dim preReconcileFWorkspace As IFeatureWorkspace = CType(versionEdit4.PreReconcileVersion, IFeatureWorkspace)
Dim reconcileFWorkspace As IFeatureWorkspace = CType(versionEdit4.ReconcileVersion, IFeatureWorkspace)
Dim enumConflictClass As IEnumConflictClass = versionEdit4.ConflictClasses
Dim conflictClass As IConflictClass = enumConflictClass.Next()
Do While Not conflictClass Is Nothing
Dim dataset As IDataset = CType(conflictClass, IDataset)
' Make sure the class is a feature class.
If (dataset.Type = esriDatasetType.esriDTFeatureClass) Then
Dim datasetName As String = dataset.Name
Dim featureClass As IFeatureClass = featureWorkspace.OpenFeatureClass(datasetName)
Console.WriteLine("Conflicts on feature class {0}", datasetName)
' Get all UpdateUpdate conflicts.
Dim updateUpdates As ISelectionSet = conflictClass.UpdateUpdates
If (updateUpdates.Count > 0) Then
' Get conflict feature classes on the three reconcile versions.
Dim featureClassPreReconcile As IFeatureClass = preReconcileFWorkspace.OpenFeatureClass(datasetName)
Dim featureClassReconcile As IFeatureClass = reconcileFWorkspace.OpenFeatureClass(datasetName)
Dim featureClassCommonAncestor As IFeatureClass = commonAncestorFWorkspace.OpenFeatureClass(datasetName)
' Iterate through each OID, outputting information.
Dim enumIDs As IEnumIDs = updateUpdates.IDs
Dim oid As Integer = enumIDs.Next()
Do While Not oid = -1 ' Loop through all conflicting features.
Console.WriteLine("UpdateUpdate conflicts on feature {0}", oid)
' Get conflict feature on the three reconcile versions.
Dim featurePreReconcile As IFeature = featureClassPreReconcile.GetFeature(oid)
Dim featureReconcile As IFeature = featureClassReconcile.GetFeature(oid)
Dim featureCommonAncestor As IFeature = featureClassCommonAncestor.GetFeature(oid)
' Check to make sure each shape is different than the common ancestor (conflict is on shape field).
If IsShapeInConflict(featureCommonAncestor, featurePreReconcile, featureReconcile) Then
Console.WriteLine(" Shape attribute has changed on both versions...")
' Geometries are in conflict ... merge geometries.
Try
Dim constructMerge As IConstructMerge = New GeometryEnvironmentClass()
Dim newGeometry As IGeometry = constructMerge.MergeGeometries(featureCommonAncestor.ShapeCopy, featureReconcile.ShapeCopy, featurePreReconcile.ShapeCopy)
' Setting new geometry as a merge between the two versions.
Dim feature As IFeature = featureClass.GetFeature(oid)
feature.Shape = newGeometry
feature.Store()
updateUpdates.RemoveList(1, oid)
conflictsRemoved = True
Catch comExc As COMException
' Check if the error is from overlapping edits.
If comExc.ErrorCode = fdoError.FDO_E_WORKSPACE_EXTENSION_DATASET_CREATE_FAILED Or _
comExc.ErrorCode = fdoError.FDO_E_WORKSPACE_EXTENSION_DATASET_DELETE_FAILED Then
' Edited areas overlap.
Console.WriteLine("Error from overlapping edits on feature {0}", oid)
Console.WriteLine(" Error Message: {0}", comExc.Message)
Console.WriteLine(" Can't merge overlapping edits to same feature.")
Else
' Unexpected COM exception, throw this to the exception handler.
Throw comExc
End If
End Try
Else
Console.WriteLine(" Shape field not in conflict: merge not necessary ... ")
End If
' Get ObjectID of the next conflicting feature.
oid = enumIDs.Next()
Loop
End If
End If
' Get the next conflict class.
conflictClass = enumConflictClass.Next()
Loop
Catch comExc As COMException
Console.WriteLine("Error Message: {0}, Error Code: {1}", comExc.Message, comExc.ErrorCode)
Catch exc As Exception
Console.WriteLine("Unhandled Exception: {0}", exc.Message)
End Try
End Sub
' Method to determine if the shape field is in conflict.
Private Function IsShapeInConflict(ByVal commonAncestorFeature As IFeature, ByVal preReconcileFeature As IFeature, _
ByVal reconcileFeature As IFeature) As Boolean
' 1st check: Common Ancestor with PreReconcile.
' 2nd check: Common Ancestor with Reconcile.
' 3rd check: Reconcile with PreReconcile (case of same change on both versions).
If IsGeometryEqual(commonAncestorFeature.ShapeCopy, preReconcileFeature.ShapeCopy) Or _
IsGeometryEqual(commonAncestorFeature.ShapeCopy, reconcileFeature.ShapeCopy) Or _
IsGeometryEqual(reconcileFeature.ShapeCopy, preReconcileFeature.ShapeCopy) Then
Return False
Else
Return True
End If
End Function
' Method returning if two shapes are equal to one another.
Private Function IsGeometryEqual(ByVal shape1 As IGeometry, ByVal shape2 As IGeometry) As Boolean
If shape1 Is Nothing And shape2 Is Nothing Then
Return True
ElseIf shape1 Is Nothing Xor shape2 Is Nothing Then
Return False
Else
Dim clone1 As IClone = CType(shape1, IClone)
Dim clone2 As IClone = CType(shape2, IClone)
Return clone1.IsEqual(clone2)
End If
End Function
End Class
See Also:
How to wire ArcObjects .NET eventsListening to versioned 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.Geodatabase ESRI.ArcGIS.Geometry ESRI.ArcGIS.System (ESRI.ArcGIS.esriSystem)
Development licensing | Deployment licensing |
---|---|
ArcView | ArcView |
ArcEditor | ArcEditor |
ArcInfo | ArcInfo |
Engine Developer Kit | Engine Runtime |