Select to view content in your preferred language

Get new objectID form EditOperation.Split()

793
5
Jump to solution
04-11-2023 08:15 PM
OscarYam
Occasional Contributor

I am working on an add-in function that splits line features. I ran some experiments and found that split will modify the original feature and add a new one. Now, I have to implement business logic that modifies the value of the new one in the same split operation. How do I retrieve the object id of the new feature and proceed with the chained operation?

0 Kudos
1 Solution

Accepted Solutions
OscarYam
Occasional Contributor

Big thanks to GintautasKmieliauskas. With GintautasKmieliauskas's inspiration, I come up with something that may be dumb but suits my case.

 

return QueuedTask.Run(() =>
{
	MapPoint splitPoint = ActiveMapView.ClientToMap(args.ClientPoint);
	if (splitPoint == null)
	{
		return;
	}
	// Get SelectedFeatures by MapSelectionChangedEvent()
	Dictionary<MapMember, List<long>> selectedFeature = SelectedFeatures;
	if (selectedFeature.Count == 1)
	{
		KeyValuePair<MapMember, List<long>> keyValuePair = selectedFeature.ElementAtOrDefault(0);
		if (keyValuePair.Key is FeatureLayer featureLayer && keyValuePair.Value.Count == 1)
		{
			// get the target line feature
			QueryFilter filter = new QueryFilter
			{
				ObjectIDs = keyValuePair.Value,
			};
			RowCursor cursor = featureLayer.Search(filter);
			cursor.MoveNext();
			Feature splitTargetLine = (Feature)cursor.Current;

			EditOperation splitEditOperation = new EditOperation();
			splitEditOperation.SelectNewFeatures = true;
			// split the line feature at split point
			splitEditOperation.Split((Layer)keyValuePair.Key, keyValuePair.Value[0], splitPoint);
			
			if (splitEditOperation.Execute())
			{
				// get the new SelectedFeatures by MapSelectionChangedEvent()
				Dictionary<MapMember, List<long>> newSelectedFeature = SelectedFeatures;
				KeyValuePair<MapMember, List<long>> NewKeyValuePair = newSelectedFeature.ElementAtOrDefault(0);
				
				// get the new line feature
				filter.ObjectIDs = NewKeyValuePair.Value;
				cursor = featureLayer.Search(filter);
				cursor.MoveNext();
				Feature newFeature = (Feature)cursor.Current;
				
				// create map point for add new point
				MapPoint connectionPoint = MapPointBuilderEx.CreateMapPoint(((MapPoint)splitPoint));
				
				// Create Chained Operation
				EditOperation createOperation = splitEditOperation.CreateChainedOperation();
				FeatureLayer deviceLayer = MapView.Active.Map.FindLayers("point layer", true).OfType<FeatureLayer>().First(l => l.Name.Equals("point layer"));
				
				// point attribute list
				Dictionary<string, object> pointValues = new Dictionary<string, object>();
				pointValues.Add("field1", "value");
				createOperation.Modify(newFeature, "field2", "value");
				createOperation.Modify(splitTargetLine, "field2", "value");
				
				// add the connection point at split point
				createOperation.Create(deviceLayer, splitPoint, pointValues);
				if (createOperation.Execute())
				{
					MessageBox.Show("Line breaked.", "Breaks", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Information);
				}
			}
		}
		else
		{
			MessageBox.Show("Please select 1 feature only.", "Breaks", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Exclamation);
		}
	}
	else
	{
		MessageBox.Show("Please select 1 feature only.", "Breaks", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Exclamation);
	}
});

 

 

View solution in original post

5 Replies
GKmieliauskas
Esri Regular Contributor

Hi,

I use workflow which is written below.

1. Set EditOperation property SelectModifiedFeatures to false.

2. Set EditOperation property SelectNewFeatures to true.

3. Make your split operation and execute it.

4. Get splited feature layer selection. It will contain object ids of new created parts.

OscarYam
Occasional Contributor

Thank you for your inspiration. I manage to achieve what I need to do. I will post a proper script later.

0 Kudos
Wolf
by Esri Regular Contributor
Esri Regular Contributor

Or you can try to use the RowCreatedEvent to capture all new rows (and their object ids).

 

try
{
  var mapView = MapView.Active;
  if (mapView == null) return;

  var polygonLayer = mapView.Map.GetLayersAsFlattenedList()
      .OfType<BasicFeatureLayer>().FirstOrDefault (lyr => lyr.Name == "TestPolygons");
  var lineLayer = mapView.Map.GetLayersAsFlattenedList()
      .OfType<BasicFeatureLayer>().FirstOrDefault(lyr => lyr.Name == "TestLines");

  if (polygonLayer == null || lineLayer == null)
  {
    throw new Exception($@"The split action requires both Layers: TestPolygons and TestLines");
  }
  QueuedTask.Run(() =>
  {
    ArcGIS.Core.Events.SubscriptionToken token = null;
    try
    {
      // create an edit operation
      EditOperation splitOperation = new()
      {
        Name = "Split polygons",
        ProgressMessage = "Working...",
        CancelMessage = "Operation canceled.",
        ErrorMessage = "Error splitting polygons",
        SelectModifiedFeatures = false,
        SelectNewFeatures = false
      };

      var splitTargetSelectionDictionary = new Dictionary<MapMember, List<long>>
        {
          { polygonLayer, polygonLayer.GetSelection().GetObjectIDs().ToList() }
        };

      var splittingSelectionDictionary = new Dictionary<MapMember, List<long>>
        {
          { lineLayer, lineLayer.GetSelection().GetObjectIDs().ToList() }
        };

      // initialize a list of ObjectIDs that to be split (selected TestPolygons)
      var splitTargetSelectionSet = SelectionSet.FromDictionary(splitTargetSelectionDictionary);

      // initialize the list of ObjectIDs that are used for the splitting (selected TestLines)
      var splittingSelectionSet = SelectionSet.FromDictionary(splittingSelectionDictionary);

      // perform the Split operation:
      // To be split (selected TestPolygons)
      // Used for the splitting (selected TestLines)
      splitOperation.Split(splitTargetSelectionSet, splittingSelectionSet);

      // start listening to RowCreate events in order to collect all new rows
      List<long> newOids = new();
      token = ArcGIS.Desktop.Editing.Events.RowCreatedEvent.Subscribe((ev) =>
      {
        newOids.Add (ev.Row.GetObjectID());
      }, polygonLayer.GetTable());

      var result = splitOperation.Execute();
      if (result != true || splitOperation.IsSucceeded != true)
        throw new Exception($@"Edit 1 failed: {splitOperation.ErrorMessage}");
      System.Diagnostics.Trace.WriteLine($@"Number of new rows: {newOids.Count}");
    }
    catch
    {
      throw;
    }
    finally
    {
      if (token != null)
        ArcGIS.Desktop.Editing.Events.RowCreatedEvent.Unsubscribe(token);
    }
  });
}
catch (Exception ex)
{
  MessageBox.Show(ex.ToString());
}

 

OscarYam
Occasional Contributor

Thank you for your assistance. But sadly RowCreatedEvent does not work in my case since the data involve Utility Network. I ran many tests before this project started but can't get RowCreatedEvent to work with the Utility Network properly.

0 Kudos
OscarYam
Occasional Contributor

Big thanks to GintautasKmieliauskas. With GintautasKmieliauskas's inspiration, I come up with something that may be dumb but suits my case.

 

return QueuedTask.Run(() =>
{
	MapPoint splitPoint = ActiveMapView.ClientToMap(args.ClientPoint);
	if (splitPoint == null)
	{
		return;
	}
	// Get SelectedFeatures by MapSelectionChangedEvent()
	Dictionary<MapMember, List<long>> selectedFeature = SelectedFeatures;
	if (selectedFeature.Count == 1)
	{
		KeyValuePair<MapMember, List<long>> keyValuePair = selectedFeature.ElementAtOrDefault(0);
		if (keyValuePair.Key is FeatureLayer featureLayer && keyValuePair.Value.Count == 1)
		{
			// get the target line feature
			QueryFilter filter = new QueryFilter
			{
				ObjectIDs = keyValuePair.Value,
			};
			RowCursor cursor = featureLayer.Search(filter);
			cursor.MoveNext();
			Feature splitTargetLine = (Feature)cursor.Current;

			EditOperation splitEditOperation = new EditOperation();
			splitEditOperation.SelectNewFeatures = true;
			// split the line feature at split point
			splitEditOperation.Split((Layer)keyValuePair.Key, keyValuePair.Value[0], splitPoint);
			
			if (splitEditOperation.Execute())
			{
				// get the new SelectedFeatures by MapSelectionChangedEvent()
				Dictionary<MapMember, List<long>> newSelectedFeature = SelectedFeatures;
				KeyValuePair<MapMember, List<long>> NewKeyValuePair = newSelectedFeature.ElementAtOrDefault(0);
				
				// get the new line feature
				filter.ObjectIDs = NewKeyValuePair.Value;
				cursor = featureLayer.Search(filter);
				cursor.MoveNext();
				Feature newFeature = (Feature)cursor.Current;
				
				// create map point for add new point
				MapPoint connectionPoint = MapPointBuilderEx.CreateMapPoint(((MapPoint)splitPoint));
				
				// Create Chained Operation
				EditOperation createOperation = splitEditOperation.CreateChainedOperation();
				FeatureLayer deviceLayer = MapView.Active.Map.FindLayers("point layer", true).OfType<FeatureLayer>().First(l => l.Name.Equals("point layer"));
				
				// point attribute list
				Dictionary<string, object> pointValues = new Dictionary<string, object>();
				pointValues.Add("field1", "value");
				createOperation.Modify(newFeature, "field2", "value");
				createOperation.Modify(splitTargetLine, "field2", "value");
				
				// add the connection point at split point
				createOperation.Create(deviceLayer, splitPoint, pointValues);
				if (createOperation.Execute())
				{
					MessageBox.Show("Line breaked.", "Breaks", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Information);
				}
			}
		}
		else
		{
			MessageBox.Show("Please select 1 feature only.", "Breaks", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Exclamation);
		}
	}
	else
	{
		MessageBox.Show("Please select 1 feature only.", "Breaks", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Exclamation);
	}
});