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?
Solved! Go to Solution.
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);
}
});
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.
Thank you for your inspiration. I manage to achieve what I need to do. I will post a proper script later.
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());
}
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.
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);
}
});