After I execute MapView.Active.GetFeatures(someGeometry), I get a dictionary of feature layers and OIDs in those feature layers that match the search geometry. From there, how do I get the actual features so I can read their attributes? Do I have to assemble the OIDs into a where clause for a query filter search, or is there a more direct way such as the IFeatureClass.GetFeature method from the ArcGIS for Desktop SDK?
Solved! Go to Solution.
Hi Tim,
You can use Inspector (for one by one feature)
// for each feature
foreach (var oid in featOids)
{
// load the inspector with the feature
var insp = new Inspector();
insp.Load(faetLayer, oid);
....
}
or use query like this:
QueryFilter queryFilter = new QueryFilter { ObjectIDs = oids };
using (RowCursor rowCursor = featLayer.Search(queryFilter))
{
while (rowCursor.MoveNext())
{
using (Row row = rowCursor.Current)
{
Feature feat = row as Feature;
....
}
}
}
Hi Tim,
You can use Inspector (for one by one feature)
// for each feature
foreach (var oid in featOids)
{
// load the inspector with the feature
var insp = new Inspector();
insp.Load(faetLayer, oid);
....
}
or use query like this:
QueryFilter queryFilter = new QueryFilter { ObjectIDs = oids };
using (RowCursor rowCursor = featLayer.Search(queryFilter))
{
while (rowCursor.MoveNext())
{
using (Row row = rowCursor.Current)
{
Feature feat = row as Feature;
....
}
}
}
I am having a similar issue.. I'd like the user to draw a box with a map tool, and from there parse the attribute table for a specific field. How exactly do you use the inspector or query filter with another field along with the oids returned from GetFeatures(geometry)?
I started developing this from an identify example where it loops through the features in the TOC and determines which are selected from the user input geometry. I have a set of 5 specific layers of interest and each has a specific field of interest I'd like to be able to pull attribute values from. Here is a snippet.. I'd like to insert the logic right under sb.ApendLine, and build an array of the attribute values from the selection.
// Create dictionary of feature classes and as-built field names
List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>();
list.Add(new KeyValuePair<string, string>("gjgislucity.DBO.SWNETG", "NTG_USER15"));
list.Add(new KeyValuePair<string, string>("gjgislucity.DBO.SWNETMHG", "MAG_USER15"));
list.Add(new KeyValuePair<string, string>("gjgislucity.DBO.SMVCONDTG", "CNG_USER4"));
list.Add(new KeyValuePair<string, string>("gjgislucity.DBO.SMVSTRUCG", "SNG_USER5"));
list.Add(new KeyValuePair<string, string>("gjgislucity.DBO.WTPIPEG", "PPG_MAP1_NO PPG_USER6"));
var mv = MapView.Active;
var selectionResult = await QueuedTask.Run(() =>
{
// Initiate string builder for message window
var sb = new System.Text.StringBuilder();
// Get the features that intersect the sketch geometry
var features = mv.GetFeatures(geometry);
// Get all layer definitions, loop through and determine which are selected
var lyrs = mv.Map.GetLayersAsFlattenedList().OfType<FeatureLayer>();
foreach (var lyr in lyrs)
{
var fCnt = features.ContainsKey(lyr) ? features[lyr].Count : 0;
if (fCnt != 0)
{
// If layer is selected, get it's name and decide if in list
var fcName = lyr.GetFeatureClass().GetName();
foreach (KeyValuePair<string, string> item in list)
{
if (item.Key == fcName)
{
total = total + fCnt;
sb.AppendLine($@"{fCnt} {(fCnt == 1 ? "record" : "records")} selected for {lyr.Name}");
}
}
}
}
Hi Dylan,
At first instead of List kvp in features)
{
string fieldName;
if(list.TryGetValue(kvp.Key.Name, out fieldName))
{
long fCnt = kvp.Value.Count;
total = total + fCnt;
sb.AppendLine($@"{fCnt} {(fCnt == 1 ? "record" : "records")} selected for {kvp.Key.Name}");
QueryFilter queryFilter = new QueryFilter { ObjectIDs = kvp.Value };
using (RowCursor rowCursor = kvp.Key.Search(queryFilter))
{
while (rowCursor.MoveNext())
{
using (Row row = rowCursor.Current)
{
string attributeValue = Convert.ToString(row[fieldName]);
// Do something with attribute value
}
}
}
}
}
Thanks for the reply, I am somewhat understanding the cursor, but I am not sure what you mean when you said 'at first instead of list kvp in features'. I am not following where this would be inserted, and if I'd still be looping through lyrs?
Solved it, thanks for your help even though I was confused about what you said initially. The cursor code was really what I needed and I ended up restructuring and looping through the GetFeatures rather than the lyrs in the TOC as the ESRI example I started off with did. Here are some snippets.
// Get the features that intersect the sketch geometry and loop through
var features = mv.GetFeatures(geometry);
foreach (KeyValuePair<BasicFeatureLayer, List<long>> fL in features)
{
// Loop through feature class list and match to user selection
featureName = fL.Key.GetTable().GetName();
foreach (KeyValuePair<string, string> item in list)
{
if (item.Key == featureName)
{
// Get selection information for message box
selected = features[fL.Key].Count;
total = total + selected;
sb.AppendLine($@"{selected} {(selected == 1 ? "record" : "records")} selected in {fL.Key.Name}");
// Get as-built field(s) and selected object ids
abFields = item.Value.Split(' ');
var oids = fL.Value;
// If water pipes are selected loop through both as-built fields and generate file paths
if (abFields.Count() > 1)
{
foreach (var ab in abFields)
{
asbuilt = GetAttributeValues(fL.Key, ab, fL.Value);
if (asbuilt != "")
{
if (ab.Contains("MAP1"))
{
path = docPath + asbuilt;
}
else
path = notesPath + asbuilt;
paths.Add(path);
}
}
}
// If other features are selected use single as-built field and generate file paths
else
{
asbuilt = GetAttributeValues(fL.Key, abFields[0], fL.Value);
if (asbuilt != "")
{
path = docPath + asbuilt;
paths.Add(path);
}
}
}
}
}
// Method to use cursor and retrieve attribute values by field
public static string GetAttributeValues(BasicFeatureLayer inFL, string fieldName, List<long> inOIDs)
{
string attValue = "";
QueryFilter queryFilter = new QueryFilter { ObjectIDs = inOIDs };
using (RowCursor rowCursor = inFL.Search(queryFilter))
{
while (rowCursor.MoveNext())
{
using (Row row = rowCursor.Current)
{
attValue = Convert.ToString(row[fieldName]);
}
}
}
return attValue;
}
Hi Dylan,
Sorry. I have replied from the mail and some part of my answer missed. I wanted to write what Dictionary is better than List in your case. For example if you need few fields from one layer, you can build dictionary like this:
Dictionary<string, List<string>>, where first is layer name, second one is list of field names. So you will need less stuff to get the same results.
I would code in different way case than one layer has few fields. I would read all values in one RowCursor. It will be faster. My GetAttributeValues procedure would have List<string> fieldNames parameter instead of string fieldName and return type will be List<string> for each of attribute fields. Then I don't need to check fields number, have 2 branches in my code and etc.
Thanks Gintautas, I am brand new to C# and of course there will be a more elegant way than my hacked together code