Hi Everyone,
I am trying to use a feature layer description to create an identical new feature class with different fields. I know there are several ways to do this. I tried doing it on DLL. The feature class and fields I want is created correctly, but when I import it into the map, the feature layer does not show, because the shape area, length and polygon fields were not transferred to the new feature class. How can I fix this?
QueuedTask.Run(() =>
{
var LayerDef = Layer.GetFeatureClass().GetDefinition();
using (Geodatabase geodatabase = new Geodatabase(new FileGeodatabaseConnectionPath(new Uri(gdb))))
{
// Creating the attribute fields
FieldDescription objectIDFieldDescription = FieldDescription.CreateObjectIDField();
FieldDescription field1 = new FieldDescription("field1", FieldType.Double);
FieldDescription field2 = new FieldDescription("field2", FieldType.Double);
List<FieldDescription> fieldDescriptions = new List<FieldDescription>()
{objectIDFieldDescription, field1, field2
};
ShapeDescription shapeDescription = new ShapeDescription(IntersectSort.GetFeatureClass().GetDefinition());
FeatureClassDescription LayerDescription = new FeatureClassDescription("Layer_Name", fieldDescriptions, shapeDescription);
SchemaBuilder schemaBuilder = new SchemaBuilder(geodatabase);
schemaBuilder.Create(LayerDescription);
bool success = schemaBuilder.Build();
});
i haven't tried this but i think these lines have an issue:
ShapeDescription shapeDescription = new ShapeDescription(IntersectSort.GetFeatureClass().GetDefinition());FeatureClassDescription LayerDescription = new FeatureClassDescription("Layer_Name", fieldDescriptions, shapeDescription);
maybe try this instead:
FeatureClassDefinition originalFeatureClassDefinition = IntersectSort.GetFeatureClass().GetDefinition();
FeatureClassDescription originalFeatureClassDescription = new FeatureClassDescription(originalFeatureClassDefinition);
FeatureClassDescription LayerDescription = new FeatureClassDescription("Layer_Name", fieldDescriptions, originalFeatureClassDescription.ShapeDescription);
Thanks Wolf for your help. I tried your method, and it has the same result. For some reason, the feature layer is not showing on the map.
It is working for me. The following snippet will create a new FeatureClass class "NewLayer" from an existing "TestPolygons" feature layer using the same shape definition but with two new fields. Then it adds the new FeatureClass to the map as "New: NewLayer" and finally copies all existing features from "TestPolygons" to "New: NewLayer".
protected override async void OnClick()
{
var originalLayerName = "TestPolygons";
var newLayerName = "NewLayer";
var originalLayer = MapView.Active.Map.GetLayersAsFlattenedList().OfType<FeatureLayer>().Where(fl => fl.Name.Contains(originalLayerName)).FirstOrDefault();
var isOk = await QueuedTask.Run<bool>(() =>
{
var LayerDef = originalLayer.GetFeatureClass().GetDefinition();
using Geodatabase geodatabase = new(new FileGeodatabaseConnectionPath(new Uri(Project.Current.DefaultGeodatabasePath)));
// Creating the attribute fields
FieldDescription objectIDFieldDescription = FieldDescription.CreateObjectIDField();
FieldDescription field1 = new("field1", FieldType.Double);
FieldDescription field2 = new("field2", FieldType.Double);
List<FieldDescription> fieldDescriptions = new()
{
objectIDFieldDescription, field1, field2
};
FeatureClassDefinition originalFeatureClassDefinition = originalLayer.GetFeatureClass().GetDefinition();
FeatureClassDescription originalFeatureClassDescription = new(originalFeatureClassDefinition);
FeatureClassDescription LayerDescription = new(newLayerName, fieldDescriptions, originalFeatureClassDescription.ShapeDescription);
SchemaBuilder schemaBuilder = new(geodatabase);
schemaBuilder.Create(LayerDescription);
bool success = schemaBuilder.Build();
return success;
});
if (!isOk)
{
MessageBox.Show($@"Failed to create {newLayerName}");
return;
}
// add the new FeatureClass to the map
var newLyr = await QueuedTask.Run(() =>
{
using Geodatabase geodatabase = new(new FileGeodatabaseConnectionPath(new Uri(Project.Current.DefaultGeodatabasePath)));
var newFc = geodatabase.OpenDataset<FeatureClass>(newLayerName);
return LayerFactory.Instance.CreateLayer<FeatureLayer>(new FeatureLayerCreationParams(newFc) { Name = $@"New: {newLayerName}" }, MapView.Active.Map);
});
// copy some data
await QueuedTask.Run(() =>
{
// create an edit operation
EditOperation copyOperation = new EditOperation()
{
Name = "Copy Data",
ProgressMessage = "Working...",
CancelMessage = "Operation canceled.",
ErrorMessage = "Error copying polygons",
SelectModifiedFeatures = false,
SelectNewFeatures = false
};
using var rowCursor = originalLayer.Search();
while (rowCursor.MoveNext())
{
using (var row = rowCursor.Current as Feature)
{
var geom = row.GetShape().Clone();
if (geom == null)
continue;
var newAttributes = new Dictionary<string, object>();
newAttributes.Add("field1", 1.0);
newAttributes.Add("field2", 2.0);
copyOperation.Create(newLyr, geom, newAttributes);
}
}
// execute the operation
if (!copyOperation.Execute())
{
MessageBox.Show($@"Copy operation failed {copyOperation.ErrorMessage}");
return;
}
});
}
It works after some minor modification to the code, but when I kept the newAttributes in "copyOperation.Create(newLyr, geom, newAttributes)," it would show this error message, "Cannot convert from System.Collection.Generic.Dictionary<string,object> to System.Action<long>". It works fine if I delete the newAttributes from the line tho. On a related note, how do I save the edits operations within the script to avoid doing it manually after the script runs? Thanks for your help Wolf!
My sample code above is for release 3.0 and newer, if you are using ArcGIS Pro 2.x then the API is bit different. Below is the snippet that works with 2.9, note the change in the copyOperation.Create line required by the 2.x API (the parameters are different):
protected override async void OnClick()
{
var originalLayerName = "TestPolygons";
var newLayerName = "NewLayer";
var originalLayer = MapView.Active.Map.GetLayersAsFlattenedList().OfType<FeatureLayer>().Where(fl => fl.Name.Contains(originalLayerName)).FirstOrDefault();
var isOk = await QueuedTask.Run<bool>(() =>
{
var LayerDef = originalLayer.GetFeatureClass().GetDefinition();
bool success = false;
using (Geodatabase geodatabase = new Geodatabase(new FileGeodatabaseConnectionPath(new Uri(Project.Current.DefaultGeodatabasePath))))
{
// Creating the attribute fields
ArcGIS.Core.Data.DDL.FieldDescription objectIDFieldDescription = ArcGIS.Core.Data.DDL.FieldDescription.CreateObjectIDField();
ArcGIS.Core.Data.DDL.FieldDescription field1 = new ArcGIS.Core.Data.DDL.FieldDescription("field1", FieldType.Double);
ArcGIS.Core.Data.DDL.FieldDescription field2 = new ArcGIS.Core.Data.DDL.FieldDescription("field2", FieldType.Double);
List<ArcGIS.Core.Data.DDL.FieldDescription> fieldDescriptions = new List<ArcGIS.Core.Data.DDL.FieldDescription>()
{
objectIDFieldDescription,
field1,
field2
};
FeatureClassDefinition originalFeatureClassDefinition = originalLayer.GetFeatureClass().GetDefinition();
FeatureClassDescription originalFeatureClassDescription = new FeatureClassDescription(originalFeatureClassDefinition);
FeatureClassDescription LayerDescription = new FeatureClassDescription(newLayerName, fieldDescriptions, originalFeatureClassDescription.ShapeDescription);
SchemaBuilder schemaBuilder = new SchemaBuilder(geodatabase);
schemaBuilder.Create(LayerDescription);
success = schemaBuilder.Build();
}
return success;
});
if (!isOk)
{
MessageBox.Show($@"Failed to create {newLayerName}");
return;
}
// add the new FeatureClass to the map
var newLyr = await QueuedTask.Run(() =>
{
using (Geodatabase geodatabase = new Geodatabase(new FileGeodatabaseConnectionPath(new Uri(Project.Current.DefaultGeodatabasePath))))
{
var newFc = geodatabase.OpenDataset<FeatureClass>(newLayerName);
return LayerFactory.Instance.CreateLayer<FeatureLayer>(new FeatureLayerCreationParams(newFc) { Name = $@"New: {newLayerName}" }, MapView.Active.Map);
}
});
// copy some data
await QueuedTask.Run(() =>
{
// create an edit operation
EditOperation copyOperation = new EditOperation()
{
Name = "Copy Data",
ProgressMessage = "Working...",
CancelMessage = "Operation canceled.",
ErrorMessage = "Error copying polygons",
SelectModifiedFeatures = false,
SelectNewFeatures = false
};
using (var rowCursor = originalLayer.Search())
{
while (rowCursor.MoveNext())
{
using (var row = rowCursor.Current as Feature)
{
var geom = row.GetShape().Clone();
if (geom == null)
continue;
var newAttributes = new Dictionary<string, object>
{
{ newLyr.GetFeatureClass().GetDefinition().GetShapeField(), geom },
{ "field1", 1.0 },
{ "field2", 2.0 }
};
copyOperation.Create(newLyr, newAttributes);
}
}
}
// execute the operation
if (!copyOperation.Execute())
{
MessageBox.Show($@"Copy operation failed {copyOperation.ErrorMessage}");
return;
}
});
}
In order to save all edits you can use:
_ = Project.Current.SaveEditsAsync();