How to undo operation in ArcMap Add-in

4755
6
Jump to solution
05-02-2012 03:45 AM
PetrVopenka
New Contributor
I am trying to programatically undo cutting of polygons if the area of newly created polygon is too small. However, the operation does no undo edits. It shows the dialog, but it does not roll back the edits. No errors are thrown in this example.

editor.addIEditEventsListener(new IEditEventsAdapter(){      public void onCreateFeature(IEditEventsOnCreateFeatureEvent theEvent)             throws IOException, AutomationException{                            IFeature createdFeature = (IFeature)theEvent.getObj();              Polygon newPolygon = (Polygon)createdFeature.getShape();           double newPolyArea = newPolygon.getArea();                      if(newPolyArea < 1000){            MessageDialog md = new MessageDialog();            md.doModal("Error editing", "Polygon too small" , null, null, 0);                        doc.getOperationStack().undo();              }           }      }


Is there any example of how to solve undos withing ArcMap Add-in?
0 Kudos
1 Solution

Accepted Solutions
KenBuja
MVP Esteemed Contributor
Here's an Add-in I'm working on that checks for a minimum polygon size (which is a setting found in a dictionary, theDict).

In my OnCreateFeature sub, I check the minimum size.
            pInFeature = CType(obj, ESRI.ArcGIS.Geodatabase.IFeature)             CanDelete = False             pFClass = CType(pDataset, ESRI.ArcGIS.Geodatabase.IFeatureClass)              If pFClass.ShapeType = ESRI.ArcGIS.Geometry.esriGeometryType.esriGeometryPolygon Then                 pArea = pInFeature.Shape                 If theDict.TryGetValue("HDX.MMU", MMUList) Then                     If pArea.Area < MMUList(1) Then                         If Windows.Forms.MessageBox.Show("The area of the polygon (" & Format(pArea.Area, "##,##0.00") & ") is less than the specified Minimum Mapping Unit." & vbNewLine & vbNewLine & "Do you want to add this polygon to your layer?", "Area Smaller than MMU", Windows.Forms.MessageBoxButtons.YesNo, Windows.Forms.MessageBoxIcon.Question) = Windows.Forms.DialogResult.No Then                             pInFeature.Delete()                             CanDelete = True                             Exit Sub                         End If                     End If                 End If             End If


Then in the OnStopOperation sub (one of the Editor2 events), I remove the last operation if the polygon will be deleted. I have stepped through this code and the OperationStack does have the last operation removed.

   Private Sub OnStopOperation()          Dim LastOp As Integer         Dim pOperation As ESRI.ArcGIS.SystemUI.IOperation          Try             LastOp = My.ArcMap.Document.OperationStack.Count - 1              If CanDelete Then                 If LastOp > -1 Then                     pOperation = My.ArcMap.Document.OperationStack.Item(LastOp)                     If pOperation.CanUndo Then                         pOperation.Undo()                         My.ArcMap.Document.OperationStack.Remove(LastOp)                     Else                         System.Windows.Forms.MessageBox.Show("Can't undo last operation", "", Windows.Forms.MessageBoxButtons.OK, Windows.Forms.MessageBoxIcon.Exclamation)                     End If                 End If             End If          Catch ex As Exception             System.Windows.Forms.MessageBox.Show(ex.ToString, "EditorExtention: OnStopOperation")         End Try      End Sub

View solution in original post

0 Kudos
6 Replies
KenBuja
MVP Esteemed Contributor
Here's an Add-in I'm working on that checks for a minimum polygon size (which is a setting found in a dictionary, theDict).

In my OnCreateFeature sub, I check the minimum size.
            pInFeature = CType(obj, ESRI.ArcGIS.Geodatabase.IFeature)             CanDelete = False             pFClass = CType(pDataset, ESRI.ArcGIS.Geodatabase.IFeatureClass)              If pFClass.ShapeType = ESRI.ArcGIS.Geometry.esriGeometryType.esriGeometryPolygon Then                 pArea = pInFeature.Shape                 If theDict.TryGetValue("HDX.MMU", MMUList) Then                     If pArea.Area < MMUList(1) Then                         If Windows.Forms.MessageBox.Show("The area of the polygon (" & Format(pArea.Area, "##,##0.00") & ") is less than the specified Minimum Mapping Unit." & vbNewLine & vbNewLine & "Do you want to add this polygon to your layer?", "Area Smaller than MMU", Windows.Forms.MessageBoxButtons.YesNo, Windows.Forms.MessageBoxIcon.Question) = Windows.Forms.DialogResult.No Then                             pInFeature.Delete()                             CanDelete = True                             Exit Sub                         End If                     End If                 End If             End If


Then in the OnStopOperation sub (one of the Editor2 events), I remove the last operation if the polygon will be deleted. I have stepped through this code and the OperationStack does have the last operation removed.

   Private Sub OnStopOperation()          Dim LastOp As Integer         Dim pOperation As ESRI.ArcGIS.SystemUI.IOperation          Try             LastOp = My.ArcMap.Document.OperationStack.Count - 1              If CanDelete Then                 If LastOp > -1 Then                     pOperation = My.ArcMap.Document.OperationStack.Item(LastOp)                     If pOperation.CanUndo Then                         pOperation.Undo()                         My.ArcMap.Document.OperationStack.Remove(LastOp)                     Else                         System.Windows.Forms.MessageBox.Show("Can't undo last operation", "", Windows.Forms.MessageBoxButtons.OK, Windows.Forms.MessageBoxIcon.Exclamation)                     End If                 End If             End If          Catch ex As Exception             System.Windows.Forms.MessageBox.Show(ex.ToString, "EditorExtention: OnStopOperation")         End Try      End Sub
0 Kudos
PetrVopenka
New Contributor
Thanks. I modified the code according to your example. So I included both "undo" and then "remove" operation, but still no success. When I step through it, I can see the operations to be removed from the operation stack, but nothing is actually undone.

In addition I tried to remove all operations step by step and I got the "Undo failed" message from ArcMap UI.

editor.addIEditEventsListener(new IEditEventsAdapter(){
         public void onCreateFeature(IEditEventsOnCreateFeatureEvent theEvent)
            throws IOException, AutomationException{
             
             IFeature createdFeature = (IFeature)theEvent.getObj();
             Polygon newPolygon = (Polygon)createdFeature.getShape();
          double newPolyArea = newPolygon.getArea();
          
          if(newPolyArea < 1000){
           MessageDialog md = new MessageDialog();
           md.doModal("Error editing", "Polygon too small" , null, null, 0);
           
           IOperationStack os = doc.getOperationStack();
           
           System.out.println("no of operations in stack before: " + os.getCount());
           
           for(int i = os.getCount(); i > 0; i--){
            System.out.println("Operation to undo: " + os.getUndoOperation().getMenuString());
            System.out.println("Can be undone: " + os.getUndoOperation().isCanUndo());
            os.undo();
            os.remove(i - 1);
           }
           
           System.out.println("no of operations in stack after: " + os.getCount());

             }

         }
     }


This is the System.out messages when I do simple polygon cut:

no of operations in stack before: 3
Operation to undo: Add Vertex
Can be undone: true
Operation to undo: Add Vertex
Can be undone: true
Operation to undo: Cut
Can be undone: true
no of operations in stack after: 0

Perhaps it has to do something with wrong editor assignment. I got reference to editor this way:

IUID uid = new UID();
uid.setValue("{F8842F20-BB23-11D0-802B-0000F8037368}");
editor = (Editor) app.findExtensionByCLSID(uid);
0 Kudos
KenBuja
MVP Esteemed Contributor
That ID should work. In my add-in, I get a reference to the editor by using

Dim theEditor As ESRI.ArcGIS.Editor.IEditor = My.ArcMap.Editor

I noticed that you didn't delete createdFeature (createdFeature.Delete())
0 Kudos
PetrVopenka
New Contributor
That would delete the feature. But I need to undo polygon cut. Perhaps I could merge the polygons back if the size is small, but that would create undesirable additional vertexes.

Instead of:
cut polygons > if size is small > merge the polygons back

I would need something like:
cut polygons > if size is small > revert to original state

I am really puzzled why undo does not undo things.

thanks anyway.
0 Kudos
KenBuja
MVP Esteemed Contributor
I have just gone through my code again using the Cut Polygon Features task. It tests the size of the newly cut polygon and if it doesn't meet the minimum size and I don't want to add it, it will delete the new feature and revert to the original polygon. This operation does not result in any additional vertices.
0 Kudos
PetrVopenka
New Contributor
Staring at your code for some time I found that the encapsulating method is the key. I was overwriting onCreateFeature of the IEditEventsAdapter, where it needs to be in in onStopOperation of the IEditEvents2Adapter.
Here is the piece of code that works for me:

editor.addIEditEvents2Listener(new IEditEvents2Adapter(){
         public void onStopOperation(IEditEvents2OnStopOperationEvent theEvent) 
            throws IOException, AutomationException{

          Editor sEditor = (Editor) theEvent.getSource();
          sEditor.getEditSelection();
          IEnumFeature enumFeature = sEditor.getEditSelection();
          enumFeature.reset();
          IFeature selFeature = enumFeature.next();

          for (int fCount = 0; fCount < sEditor.getSelectionCount(); fCount++)
          { 
           Polygon sPolygon = (Polygon)selFeature.getShape();
           double sArea = sPolygon.getArea();

           if(sArea < 1000){
            MessageDialog md = new MessageDialog();
            md.doModal("Error editing", "Polygon too small, stopping operation" , null, null, 0);
            IOperationStack os = doc.getOperationStack();
            os.undo();
           }
           selFeature = enumFeature.next();
          }
         }
     }
 );


Thanks.
0 Kudos