Cannot update Z values from Surface in RowEvent

653
4
12-02-2022 06:11 AM
FridjofSchmidt
Occasional Contributor

This is a similar issue to what succip posted the other day. I'm trying to update Z values of a feature geometry in a RowEvent (RowCreatedEvent or RowChangedEvent), but while awaiting the Z values, it seems the feature is getting disposed. When trying to update the feature's shape in feature.SetShape(newShape), I get an ArcGIS.Core.ObjectDisconnectedException ("This object has been previously disposed and cannot be manipulated."). My code:

public async void OnRowChanged(RowChangedEventArgs args)
{
	var feature = (Feature)args.Row;
	var newShape = this.PolylineDensifier.Densify(feature.GetShape() as Polyline, MAX_LENGTH);
	var result = await MapView.Active.Map.GetZsFromSurfaceAsync(newShape);
	if (result.Status == SurfaceZsResultStatus.Ok) newShape = (Polyline)result.Geometry;
	newShape = (Polyline)GeometryEngine.Instance.Generalize3D(newShape, GENERALIZE_OFFSET);
	UpdateMs(newShape);
	newShape = (Polyline)GeometryEngine.Instance.SimplifyAsFeature(newShape, true);
	feature.SetShape(newShape);
	// ...
}

My interpretation: Since the event handler has a void return type, the method is not awaiting the GetZsFromSurfaceAsync call and the edit operation terminates (disposing the feature) before the geometry is being updated. All my other manipulations work well if I skip updating the Z values.

I also tried

var result = MapView.Active.Map.GetZsFromSurfaceAsync(newShape).Result;

But this call never terminates (deadlock).

According to Wolfs suggestion in the aforementioned post, I migth start a new EditOperation and re-update the feature there, but to me this looks awkward because my intention was to do all manipulations within the RowEvent's operation. Also, I need the manipulations to appear as one operation on the stack, so that the user cannot undo just my manipulations while the initial create/update operation is not getting undone.

How can this be achieved? Is there a way to get Z values synchronously? In ArcMap this was possible with the IFunctionalSurface.Z method, but I haven't found an equivalent in Pro (see also this post).

Updating the Zs automatically in the map via ElevationCapturing.CaptureMode = Surface does not seem an option because I want to densify the geometry first and then 3D-generalize it. And updating the Zs in the BeforeSketchCompletedEvent does not seem an option because I need this behavior only for a certain feature layer, both for new features and geometry updates.

0 Kudos
4 Replies
CharlesMacleod
Esri Regular Contributor

Hi Fridjof, your analysis sounds correct  and I think Wolf's recommendation of a second edit operation is the way to go. The key is to "chain" the edit operations together that need to behave on the UNDO/REDO stack as if they are a single transaction (even tho' the chained operations actually span multiple edits). It is explained here (the "classic" use case being adding an attachment to a new feature - in that scenario, the feature must exist such that the relate to the row in the attachment table can be created...resulting in two edits).

https://github.com/esri/arcgis-pro-sdk/wiki/ProConcepts-Editing#chaining-edit-operations

Note: Just thought I would mention another possibility - it might be possible to use a RowToken - A RowToken acts as a placeholder for a new feature (if "feature" in your snippet example represents a new feature - sorry, I cant tell from the context). The basic pattern for use of a rowtoken is:

var rowToken = editOp.Create(......);//call Create - returns a rowtoken or "placeholder"

//Do surface Z query + generalization here

dictOfAttributes["SHAPE"] = newShape;

editOp.Modify(rowToken, dictOfAttributes);//Use the placeholder here to refer to the feature "TO BE" created.

editOp.Execute(); //Now Create _and_ modify get executed together.

 

RowToken is explained here: https://github.com/esri/arcgis-pro-sdk/wiki/ProConcepts-Editing#rowtokens 

0 Kudos
FridjofSchmidt
Occasional Contributor

Thank you Charles, I will give it a try with chained edit operations, since I need this both for new and changed features. The key seems to be that the chained operation cannot be created from the RowEvent's operation inside the RowEvent itself because the parent operation is already executing (trying to do so throws an exception as documented here).

A pattern that might work (I'm still testing) is:

  • Create a chained EditOperation in the EditStartedEvent
  • In the RowChangedEvent, get an updated shape with surface Z query - letting the parent operation complete and dispose the feature
  • After the surface Z query and further manipulations, but still in the RowChangedEvent handler, get a fresh copy of the feature from the feature layer, and update its geometry in the previously created chained EditOperation

I just want to make sure that I'm not creating chained edit operations when I don't need them (e.g., when an edit operation is started on a layer I'm not interested in). Whew, it's getting more complicated than I thought...

0 Kudos
sjones_esriau
Esri Contributor

Hi Fridjof,

Before looking at chaining edit operations, Id take a look at removing the 'feature' object from the event (the cast) and just manipulate the row geometry. Then put the new shape geometry back on the row object.

0 Kudos
FridjofSchmidt
Occasional Contributor

Hi sjones, unfortunately this doesn't help, because the row is getting disposed while awaiting GetZsFromSurfaceAsync.

0 Kudos