I have two Node layers in my map with the second layer being a copy of the first. I am enabling users to merge similar nodes to help clean up data, but all alterations are done on the copy layer in case the user later decides those nodes shouldn't be merged. So in my code I have:
//MergeRow is the new row and SelectedNodes is the list of rows to be deleted
public async Task<bool> MergeNodes(DataRow MergedRow, List<DataRow> SelectedNodes) {
var modifyFeature = new EditOperation();
modifyFeature.Name = "Merged Nodes";
//Other stuff
modifyFeature.Delete(MergeNodeLayer, Int64.Parse(SelectedNodes[0][oidNum].ToString()));
modifyFeature.Execute();
return true;
}
Even though I pass in the MergeNodeLayer, it deletes the node from both the control layer and the new layer. Is this a bug with delete or am I doing something wrong? The nodes on both layers have the same oids since it is a direct copy so it is deleting the correct one from each layer, but it should only be deleting the one for the layer I passed in.
Thank you,
Susan
Solved! Go to Solution.
Hi Susan,
To get the underlying featureclass path from a feature layer you'll have to concatenate the datastore path and the featureclass name. You can then feed this into the "mva" then into the geoprocessing tool. Note that if the featureclass was in a featuredataset in the datastore you would include that in the path too (determined from featureclass.GetFeatureDataset()).
Here's an example
QueuedTask.Run(async () =>
{
//find hydrant layer
var hydLayer = MapView.Active.Map.FindLayers("Hydrant").FirstOrDefault() as FeatureLayer;
//get the underlying featureclass path for the layer
var hydClass = hydLayer.GetFeatureClass();
//get the datastore for the featureclass
var hydStore = hydClass.GetDatastore();
//concat hydrant path (datastore and featureclass name)
var hydPath = hydStore.GetPath().AbsolutePath + @"/" + hydClass.GetName();
//make the value array and pass to the GP tool
var mva = Geoprocessing.MakeValueArray(@hydPath, $@"{hydPath}2");
await Geoprocessing.ExecuteToolAsync("Copy_management", mva);
});
Susan,
It sounds like both layers in the map may be pointing to the same feature class. You can check this under the layer properties source tab for each.
How did you copy the layer?
await QueuedTask.Run(() => {
if (LayerFactory.Instance.CanCopyLayer(frmLayer)) {
var newLayer = LayerFactor.Instance.CopyLayer(fmLayer, MapView.Active.Map);
newLayer.SetName (String.Format("{0}_Copy", frmLayer.Name)
}
How do I make it create a copy of the featureclass as well?
Thank you,
Susan
Susan,
The easiest way is to use the geoprocessing copy features tool.
var mva = Geoprocessing.MakeValueArray(@"Hydrant", @"D:\arcgis\ArcTutor\Editing\Zion.gdb\hydrant2");
Geoprocessing.ExecuteToolAsync("CopyFeatures_management", mva);
This will copy selected features from the input layer (or all if none are selected) into the new feature class and add a new layer to the current map. You wont need to copy the layer with the LayerFactory.
I'm guessing the C# version of that is:
foreach (BasicFeatureLayer fmLayer in lyr) //there is a node layer and a link layer
{
string newLayerName = String.Format("{0}_NewCopy", frmLayer.Name);
string pathToFeature = $@"{gdbPath}\{newLayerName}";
List<object> args = new List<object>() { gdbPath, newLayerName, featType.ToString(), "",
hasMeasure, "DISABLED"};
var res = await Geoprocessing.ExecuteToolAsync("management.CreateFeatureClass",
Geoprocessing.MakeValueArray(args.ToArray()));
await QueuedTask.Run(() => {
var mva = Geoprocessing.MakeValueArray(fmLayer, pathToFeature );
Geoprocessing.ExecuteToolAsync("management.CopyFeatures", mva);
}
}
Two questions:
var modifyInspector = new Inspector(true);
modifyInspector.Load( MergeNodeLayer, refId); // this looks at the first column data and, with it being
//renumbered, will not edit the same node selected from the first layer as in the
//merge layer.
Example:
Original Layer
FID Shape Name Type
0 .... Street PolyLine
1 .... Road PolyLine
Copied Layer
OBJECTID Shape Name Type
1 .... Street PolyLine
2 .... Road PolyLine
I hadn't considered copyfeatures re-initializing the object ids, but that makes sense since the input can be a layer. Surprisingly it also happens if you specify the featureclass as the input.
Two alternatives. Use the geoprocessing copy tool instead, which only takes featureclasses as input. This will preserve the object ids and should be faster too as it doesn't interrogate the layer.
var mva = Geoprocessing.MakeValueArray(@"D:\arcgis\ArcTutor\Editing\Zion.gdb\Hydrant", @"D:\arcgis\ArcTutor\Editing\Zion.gdb\hydrant2");
Geoprocessing.ExecuteToolAsync("Copy_management", mva);
The featureclass to featureclass tool is the other option but I haven't tried that.
There's no SDK API calls to copy featureclasses apart from going through the geoprocessing tools as the UI does.
I changed my code to (I'm guessing C# translation of your code above):
foreach (BasicFeatureLayer fmLayer in lyr) //there is a node layer and a link layer
{
string newLayerName = String.Format("{0}_NewCopy", frmLayer.Name);
string pathToFeature = $@"{gdbPath}\{newLayerName}";
string pathFromFeature = $@"{gdbPath}\{frmLayer.Name}";
var mva = Geoprocessing.MakeValueArray(pathFromFeature , pathToFeature );
var res = await Geoprocessing.ExecuteToolAsync("management.Copy", mva);
}
And it does nothing so I'm guessing I am doing something wrong. Any ideas what?
Thank you,
Susan
Hmm, it looks reasonable. The syntax for the GP tool name ("management.Copy" or ""Copy_managment") will work either way so thats not the issue.
Make sure the pathFromFeature and pathToFeature strings make sense for a featureclass and you could also try those manually in the geoprocessing copy tool to see if it works there.
Your using the layer name as the feature class input which may not always be the same, particularly if the layer name has a space, the corresponding featureclass name wont.
Lastly, check the res variable (an IGPResult) to see the error message.
The problem is that I was trying to Copy the FeatureLayer and that doesn't work with Copy. Do you know how I can get the Feature Dataset from the Feature Layer?
Thank you,
Susan
I'm not sure if this is correct, but I have been trying this which is also not working.
foreach (BasicFeatureLayer fmLayer in lyr) //there is a node layer and a link layer
{
string newLayerName = String.Format("{0}_NewCopy", frmLayer.Name);
string pathToFeature = $@"{gdbPath}\{newLayerName}";
string pathFromFeature = $@"{gdbPath}\{frmLayer.Name}";
await QueuedTask.Run(() =>
{
using (Table tbl = fmLayer.GetTable())
{
var mva = Geoprocessing.MakeValueArray(tbl, pathToFeature );
var res = await Geoprocessing.ExecuteToolAsync("management.Copy", mva);
}
}
}
res.Exception is null, res.Status = WaitingToRun, and res.Result = null.
I noticed that mva contains only strings when it is sent to Copy_management. Do you know how I correct this?
Thank you,
Susan