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);
});
I must be doing something wrong. Here is my code:
public async Task<string[]> CopyLayer()
{
var lyr = _arcFac.MainMapView.Map.GetLayersAsFlattenedList();
string[] newLayers = new string[lyr.Count]();
await QueuedTask.Run(() =>
{
foreach (BasicFeatureLayer fmLayer in lyr)
{
var hydLayer = MapView.Active.Map.FindLayers(fmLayer.Name).FirstOrDefault() as FeatureLayer; //I also tried this with = fmLayer as FeatureLayer and got the same result
var hydClass = hydLayer.GetFeatureClass();
var hydStore = hydClass.GetDatastore();
var hydPath = hydStore.GetPath().AbsolutePath + @"/" + hydClass.GetName();
var mva = Geoprocessing.MakeValueArray(@hydPath, $@"{hydPath}2");
var res = Geoprocessing.ExecuteToolAsync("Copy_management", mva);
}
});
}
Though this does create lock files, it does not create new layers for me. I was originally running it with files on a network share drive, I moved those files locally and tried again. I get the same result. "res" does not contain an error and just says awaiting thread to complete. Any ideas? I cannot send you my direct code or my shape files. Sorry.
Thank you,
Susan
Hi Susan,
Finding the layers twice is a bit of overkill so assuming you just want to work with featurelayers, you can change the first list to:
var lyr = MapView.Active.Map.GetLayersAsFlattenedList().OfType<FeatureLayer>();
Your foreach loop then looks like:
foreach (var fmLayer in lyr)
then you can get the featureclass from your fmLayer instead of hydlayer etc.
Next, set a break point and run the add-in through the debugger, stepping through the code to see if the values make sense. Ideally through each loop the mva variable should look correct:
My mva is:
"C:/Temp/all_nodes_shp"
"C:/Temp/all_nodes_shp2"
and my res2 is:
AyncState = null
CancellationPending = false
CreationOptions = None
Exception = null
ID = some number
Result = null
Status = WaitingToRun
Does it matter that I am using shape files? Should the hydPath include the .shp extention?
Thank you,
Susan
That was it. It needed the extension.
Thank you,
Susan
Do you know how to programmatically get the file extension since I won't know if the user is using shapefiles, layers, or a gdb file?
Thank you,
Susan
Hi Susan,
Yes, again its a bit convoluted.
//get the datastore for the featureclass
var hydStore = hydClass.GetDatastore();
if (hydStore is FileSystemDatastore)
{
var cp = hydStore.GetConnector() as FileSystemConnectionPath;
var t = cp.Type; //shapefile or raster?
}
From the featureclass you get the datastore which is a type of filesystem (shapefiles or raster), local or enterprise. For the filesystemdatastore you can further identify a shapefile or raster source. You cant directly get the shapefile extension.
Ive asked the geodatabase team to make this whole thing easier...
Thank you! This works great for shape files and raster files, but I was just testing for files in a geodatabase and it does not work. We are so close.
foreach (BasicFeatureLayer fmLayer in lyr)
{
var hydLayer = fmLayer as FeatureLayer
var hydClass = hydLayer.GetFeatureClass();
var hydStore = hydClass.GetDatastore();
string fileExtention = "";
if (hydStore is FileSystemDatastore)
{
var cp = hydStore.GetConnector() as FileSystemConnectionPath;
if (cp.Type == FileSystemDataStpreType.Shapefile)
fileExtention = ".shp";
}
//fileExtention is an empty string in the case of a geodb.
var hydPath = hydStore.GetPath().AbsolutePath + @"/" +
hydClass.GetName() + fileExtention;
var mva = Geoprocessing.MakeValueArray(@hydPath, $@"{hydPath}2") + fileExtention;
var res = Geoprocessing.ExecuteToolAsync("Copy_management", mva);
}
Hi Susan,
I'd probably just do the extension as part of the mva string so it becomes:
//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 + fileExtention, $@"{hydPath}2" + fileExtention);
await Geoprocessing.ExecuteToolAsync("Copy_management", mva);
This should work for all types.
It works for everything except when the files are part of a gdb file. I have a SmallTest.gdb with two layers in it. hydstor is a Geodatabase. When I try the code above to create copies of them, it doesn't. There are no errors. The res is:
AyncState = null
CancellationPending = false
CreationOptions = None
Exception = null
ID = some number
Result = null
Status = WaitingToRun
So it is like before when I didn't have the proper file extension.
Thank you,
Susan