Pro 2.2 issues?

1288
19
07-16-2018 12:15 PM
MKa
by
Occasional Contributor III

Has anyone had any issues after their upgrade to Pro 2.2.  It seems that most of my difference and merge functions are not performing as they did in 2.1?  I am wondering if anyone else is having this issue or I need to do something different when saving the result of that operation?

0 Kudos
19 Replies
Wolf
by Esri Regular Contributor
Esri Regular Contributor

Hi M,

 I you can publish a code snippet that you suspect of not working the same I will try the snippet in both versions and let you know if there's an issue.

Thanks,

Wolf

0 Kudos
MKa
by
Occasional Contributor III

Sorry I couldn't get back to you yesterday.  What i am trying to do is simply get the difference between to of the same feature from our feature service.  Two of the same type Polygons cannot occupy the same space.  So when you draw one polygon over one or more of the same type polygon(s), it gets the total of those intersecting polygons, and gets the difference of the new polygon minus the intersecting polygons, this is a small part of that code.  

I have an object that gets the difference geometry of features of the same type, it then calls this difference procedure and stores the new geometry, but that new geometry doesn't save since the move to 2.2.  New code works and the new polygon is clipped/difference, but when we execute the operation if fails to make the change.  I can't upgrade to this version until i get this resolved.  i am sure it is something simple.

public void Difference(Geometry inDifferenceGeometry)
        {            
            try
            {
                //Get the difference of this ProMap Item minus the inDifferenceGeometry
                if (!inDifferenceGeometry.IsNullOrEmpty())
                {
                    Geometry originalShape = _dataInspector.Shape;
                    Geometry differenceShape = GeometryEngine.Instance.Difference(originalShape, inDifferenceGeometry);

                    _dataInspector.Shape = differenceShape;
                    //create and execute the edit operation
                    // create an edit operation
                    EditOperation differenceOperation = new EditOperation()
                    {
                        Name = "Difference Operation",
                        ProgressMessage = "Working...",
                        CancelMessage = "Operation canceled.",
                        ErrorMessage = "Error In Difference",
                        SelectModifiedFeatures = false,
                        SelectNewFeatures = false
                    };
                    differenceOperation.Modify(_dataInspector);

                    CommitEditOperation(differenceOperation);
                }
            }
            catch (Exception e)
            {
                LogError("Difference", e);
            }

            Log.Debug("ProMapItem - Difference - Finished");
        }

public void CommitEditOperation(EditOperation eo)
        {
            long currentObjectID = OID;
            try
            {
                PMModifiedBy = Settings.CurrentUserName;

                //This line makes sure the OnRowChangeEvent in Module is not retriggered, the OnRowChangeEvent checks this list before it continues
                Module.CurrentlyUpdatingOIDList.Add(currentObjectID);
               
                bool operationResult = eo.Execute();                
            }
            catch (Exception e)
            {
                LogError("CommitEditOperation - " + eo.Name, e);
                throw;
            }
            finally
            {
                Module.CurrentlyUpdatingOIDList.Remove(currentObjectID);
            }
        }
0 Kudos
MKa
by
Occasional Contributor III

By watching the Area of the inspector shape, I can see that this line does set the new shape to the difference value

_dataInspector.Shape = differenceShape;

But when i run the following line, that shape.area quickly reverts back to the original value

bool operationResult = eo.Execute();
0 Kudos
NarelleChedzey
Esri Contributor

What is the value of 'operationResult'. when you run the code?  If it is false is there a useful string in op.ErrorMessage?   

From what you've posted here, it appears that the geometry function is calculating values successfully but it is the edit which fails to be committed.  Are you able to edit this same data when using ArcGIS Pro  (modify an attribute or use move/rotate/scale to modify the geometry). 

Narelle

0 Kudos
Wolf
by Esri Regular Contributor
Esri Regular Contributor

I tried the snippet and it appears to work fine.  Do you call the 'Difference' method from within the context of an edit event or simply as a result of inspector.Load ?  Also is the data source of the feature in _dataInspector a feature service?

I want to setup the context in my sample to better match your workflow.

Wolf

0 Kudos
MKa
by
Occasional Contributor III

I had to rollback to 2.1 as we are moving to a Production Release and are users will have to start on 2.1 until I have time to move to 2.2 and fix the issue.  I am able to Move/Resize/Rotate/Add Vertices, but the changes I make to that feature from a feature service as a result of this action, don't seem to save.  After i perform one of these Move/Resize/Rotate/Add Vertices actions, my code must sometimes alter that feature to not overlap (Clip) another feature of the same type or to be fully within a different feature (confine).  But with 2.2 this functionality doesn't save.  I am able to do the intersection/difference edits, but the saves simply don't save when I execute or commit them.  I work with the Create/Change functions in my module too, so on create or change event I populate the Feature Service item being created into an inspector like below.  The below code is for create, but the change code works in much the same way.  Both create and change are not saving my edit actions when i commit them.

(And Sorry, but for some reason the code block option is not available in the reply here?)

protected static async void OnRowCreateEvent(RowChangedEventArgs args)
{
   try
   {
      Inspector inspr = await GetInspectorForRow(args, true);
      ProMapItem pmi = ProMapFactory.GetProMapItem(inspr);

      if (pmi != null && Settings.CurrentMapSettings != null)
      {         

         //Make the initial commit to get the field to be visible with the definition query
         await pmi.CommitChangesAsync();

         pmi.ShowEditForm = true;
         pmi.HasShapeChanged = true;
         pmi.IsNew = true;

         //Run the difference and intersection rules so the polygon is confined or cliped

         await pmi.Edit();
      }
}
catch (Exception e)
{

}

private static async Task<Inspector> GetInspectorForRow(RowChangedEventArgs args, bool isNewRow)
{
      Inspector inspr = new Inspector();
      try
      {
         long _updateOID = args.Row.GetObjectID();

         //Get the layer of the selected item
         FeatureClass newFC = (FeatureClass)args.Row.GetTable();
         string updateItemName = newFC.GetDefinition().GetAliasName();
         FeatureLayer firstFeatureLayer = FeatureServiceManagement.GetFeatureLayer(updateItemName);

         //Load the inspector
         await inspr.LoadAsync(firstFeatureLayer, _updateOID);
      }
      catch (Exception e)
      {         
      }
      return inspr;
}

0 Kudos
Wolf
by Esri Regular Contributor
Esri Regular Contributor

Sorry about the delayed reply.  I looked over your snippets of code and tried to implement a sample to perform the same workflow.  In my workflow I use RowChangedEvent and RowCreatedEvent subscriptions to make changes to the geometry of the subject row.  The workflow looks like this:  I modify an existing polygon or create a new one.  Once the RowChanged / Created Event a firing, I use the new geometry and union all existing intersects of the new polygon with other polygons in that same layer.  I then 'subtract' that union of intersects (if any) with my new geometry and overwrite the sketched geometry.  So here is what it looks like in my add-in: First I 'create' a new polygon to my existing layer:

After I complete the sketch my Row Created event kicks in and the add-in logic to change my geometry run to prevent that my newly created geometry doesn't overlay any other polygons.  I also update a description field in my new or modified feature to show if the sketched geometry was changed or not.

Hopefully I captured what you do in your add-in.  Just in case I did here are some snippets from the sample:

// this is the feature layer that the add-in will process ... needs to be set somewhere in your add-in
private FeatureLayer _workedOnFeatureLayer = null;

// setup event listening ... somewhere in your code
QueuedTask.Run(() => {  
  _onRowChangedEvent = RowChangedEvent.Subscribe(OnRowChangedEvent, _workedOnFeatureLayer.GetTable());
  _onRowCreatedEvent = RowCreatedEvent.Subscribe(OnRowCreatedEvent, _workedOnFeatureLayer.GetTable());
});

// ....

/// <summary>
/// Called for each row change
/// </summary>
/// <param name="args"></param>
private void OnRowChangedEvent(RowChangedEventArgs args)
{
  UpdateStatusText ($@"Row changed: {args.EditType}");
  UpdateRowIfNeeded(args);
}

/// <summary>
/// called for each newly created row
/// </summary>
/// <param name="args">
/// </param>
private void OnRowCreatedEvent(RowChangedEventArgs args)
{
  UpdateStatusText ($@"Row created: {args.EditType}");
  UpdateRowIfNeeded(args);
}

private void UpdateRowIfNeeded (RowChangedEventArgs args)
{
  try  {
    var row = args.Row;
    var geom = row["Shape"] as Geometry;
    var rowCursorOverlayPoly = _workedOnFeatureLayer.Search (geom, SpatialRelationship.Overlaps);
    Geometry geomOverlap = null;
    while (rowCursorOverlayPoly.MoveNext())
    {
      var feature = rowCursorOverlayPoly.Current as Feature;
      var geomOverlayPoly = feature.GetShape();
      if (geomOverlayPoly == null) continue;
      var geomDifference = GeometryEngine.Instance.Intersection(geom, geomOverlayPoly);
      if (geomDifference == null) continue;
      if (geomOverlap == null) {
        geomOverlap = geomDifference;
        continue;
      }
      geomOverlap = GeometryEngine.Instance.Union(geomOverlap, geomDifference);
    }
    if (!geomOverlap.IsNullOrEmpty())
    {
      args.Row["Description"] = "Corrected input polygon";
      row["Shape"] = GeometryEngine.Instance.Difference(geom, geomOverlap);
    }
    else      args.Row["Description"] = "No overlapping polygons found";
  }
  catch (Exception e)  {
    MessageBox.Show($@"Error in UpdateRowIfNeeded for OID: {args.Row.GetObjectID()} in {_workedOnFeatureLayer.Name}: {e.ToString()}");
  }
}‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

Looks like my add-in works for both file and database connections, I will try a feature service tomorrow.

0 Kudos
MKa
by
Occasional Contributor III

I have since had to roll back to the 2.1 version as we are in Production now and don't want to upgrade the users version yet.  I plan on upgrading and testing again soon.  The one thing that i do see that is different is that you are using the row whereas I am loading the inspector with the OID from the Arg.  I am thinking it must be something with the Geometry on a non new arg when I load the inspector? 

protected static async void OnRowCreateEvent(RowChangedEventArgs args)
        {
            try
            {
                Inspector inspr = await GetInspectorForRow(args);
                ProMapItem pmi = ProMapFactory.GetProMapItem(inspr);

                if (pmi != null && Settings.CurrentMapSettings != null)
                {
                    //pmi.CreatedBy = Settings.CurrentUserName;
                    pmi.PlantCode = Settings.CurrentMapSettings.PlantCode;
                    pmi.HarvestYear = Settings.CurrentMapSettings.HarvestYear;
                    pmi.HarvestTrimester = Settings.CurrentMapSettings.HarvestTrimester;
                    pmi.MaterialGroup = Settings.CurrentMapSettings.MaterialGroup;

                    //Override of Created/Modified
                    pmi.PMCreatedBy = Settings.CurrentUserName;
                    pmi.PMModifiedBy = Settings.CurrentUserName;

                    //Make the initial commit to get the field to be visible with the definition query
                    await pmi.CommitChangesAsync();

                    pmi.ShowEditForm = true;
                    pmi.HasShapeChanged = true;
                    pmi.IsNew = true;
                    await pmi.Edit();
                }
            }
            catch (Exception e)
            {
                ProMapBlackLogWriter.LogError("ProMapBlackModule - onRowCreateEvent", e);
            }
        }

private static async Task<Inspector> GetInspectorForRow(RowChangedEventArgs args)
        {
            Inspector inspr = new Inspector();
            try
            {
                long _updateOID = args.Row.GetObjectID();

                //Get the layer of the selected item
                FeatureClass newFC = (FeatureClass)args.Row.GetTable();
                string updateItemName = newFC.GetDefinition().GetAliasName();
                FeatureLayer firstFeatureLayer = FeatureServiceManagement.GetFeatureLayer(updateItemName);

                //Load the inspector                
                await inspr.LoadAsync(firstFeatureLayer, _updateOID);
            }
            catch (Exception e)
            {
                ProMapBlackLogWriter.LogError("ProMapBlackModule - GetInspectorForRow", e);
            }
            return inspr;
        }‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍
0 Kudos
Wolf
by Esri Regular Contributor
Esri Regular Contributor

I took my sample code that I used to duplicate your workflow and published the sample on 'community samples' GitHub repo here: Modify Newly Added Features.  Hopefully this sample helps when you refactor the code for 2.2.  There are a few issues that I would like to highlight in the ProConcepts Editing document, specifically in the Row Events section at the end of the document:

1. "The row events are published during the execution of the edit operation (whereas the EditCompletedEvent is published after the entire edit operation has completed).This means that the row event intercepts your row creation/update before the transaction is completed, you can still cancel any changes from within any row event.  You cannot commit any data changes while you are processing any row events which I think is what you do in your code here: 

//Make the initial commit to get the field to be visible with the definition query
await pmi.CommitChangesAsync();

If your intend is to display a newly created feature that satisfied the current 'definition query' on that layer, you should use an appropriate 'editing / creation template' that contains valid values so that the 'definition query' results are true (hence your new feature is shown on the map view) from the get-go.  You can make changes to the args.row fields directly if need be (see the sample) and you can call .Store() on the row to save these changes, but this will result in a recursive row event (again see the sample for details).  

2. "If you need to edit additional tables within the RowEvent you must use the ArcGIS.Core.Data API to edit the tables directly. Do not use a new edit operation to create or modify features or rows in your RowEvent callbacks." I think I saw your code snippets using an another EditOperation in one of the functions that are instantiated from the row events.  In 2.2 this will not work.  Instead, as indicated by the documentation, you must use the ArcGiS.Core.Data API to change other data sources directly (in the sample I show this when I update the tracking/logging table).  

Hopefully this will help you out.

Wolf

0 Kudos