1

I am trying to get information from fields within specific feature classes based on an XY point. The user will click on the add-in tool, click on a location in ArcMap, and the tool will find the information from about 5 different feature classes. This information will be taken and sent to a windows form for the user to see. I already have code to get the XY click in both screen and map coordinates but don't know how to go about getting the field information. If I could get 5 strings back to send to the form, that would be perfect. Any help and insight would be great. Also, feel free to improve my existing code.

Here is what I have so far:

namespace LocationResources
{
    public class LocationIdentify : ESRI.ArcGIS.Desktop.AddIns.Tool
    {
        //Define and initialize global variables
        private string director = "";
        private string city = "";
        private string county = "";
        private string school = "";
        private string subdivision = "";

        private IPoint screenPoint;
        private IPoint mapPoint;

        public LocationIdentify()
        {
        }

        protected override void OnUpdate()
        {
            Enabled = ArcMap.Application != null;
        }

        protected override void OnMouseDown(MouseEventArgs arg)
        {
            if (arg.Button == System.Windows.Forms.MouseButtons.Left)
            {
                try
                {
                    // Get mouse click location in pixels (screen coordinates)
                    screenPoint = new Point();
                    screenPoint.X = arg.X;
                    screenPoint.Y = arg.Y;

                    // Get map document information for transforming pixels to feet coordinates
                    IApplication m_application = Hook as IApplication;
                    IScreenDisplay screenDisplay = (m_application.Document as IMxDocument).ActiveView.ScreenDisplay;

                    // Transform mouse click location into feet (map coordinates)
                    mapPoint = screenDisplay.DisplayTransformation.ToMapPoint(arg.X, arg.Y);
                }
                catch
                {
                    MessageBox.Show("Something went wrong getting the XY point.");
                }

                try
                {
                    // Get spatial information
                    GetSpatialInformation(screenPoint);  // If screenPoint works mapPoint may not be needed
                }
                catch
                {
                    MessageBox.Show("Something went wrong getting the spatial information");
                }

                // Launch location information form
                LocationInformation info = new LocationInformation(director, city, county, school, subdivision);
                info.Show();
            }
        }

        private void GetSpatialInformation(IPoint coordinates)
        {
            // TO-DO --> Get spatial information
        }
    }
}
0

It looks like you want to use your function GetSpatialInformation to go through the map layers and find the values... it looks OK so far but watch your try/catching - should the first one fail you should not enter the 2nd. It would probably be best to keep a boolean variable eg: pProcessOK = true; and then set it to false on a catch then before each block start with if (pProcessOK).

I've put together this little example for you to build from, I don't have all the information to do the layer logic - I'll leave that up to you on how to work out which layer you're referencing. Dark Fader is correct about that sample however I think it's a bit too advanced for where you currently are... please go back to it later because there's quite a few very good hints there.

For a start to go through your layers there's two ways:

  • IMap.Layer(Index) which is good, you count them 0 to IMap.LayerCount - 1 but doesn't do too well with group layers.
  • IMap.Layers(UID,Recurse) is also good, this works well with group layers and also filters down the layers so you don't need to decide what type of layer you have.

Note in C# these properties start with get_ so IMap.Layer(index) is written IMap.get_Layer(index) as the get/put are separated.

For each layer you can find the features for a given point using an ISpatialFilter (also supports an additional where clause) in an IFeatureLayer.Search which returns an IFeatureCursor, grab the first IFeature and then get the value at the index of the field name.. sounds simple doesn't it? Here's the example:

private void GetSpatialInformation(IPoint coordinates)
{
    // you have created your point from coordinates but have not set the spatial reference
    // that's bad and can cause problems later, so we'll set them now
    IMxDocument pDoc = ArcMap.Document;
    IMap pMap = pDoc.FocusMap;
    coordinates.SpatialReference = pMap.SpatialReference;

    // some strings to hold the return values
    // instead find some way to put them somewhere
    // on your form like Form1.TextBox1.Text
    // only 2 examples this time
    string pdirectorValue;
    string pcityValue;
    string director = "";
    string city = "";

    // create a spatial filter
    // I'm using a buffer to find lines/points but if you've only got
    // polygons it would work just as well with a point for the geometry
    ITopologicalOperator pTopOp = coordinates as ITopologicalOperator;
    ISpatialFilter pSpatFlt = new SpatialFilterClass();
    pSpatFlt.SpatialRel = esriSpatialRelEnum.esriSpatialRelIntersects;
    pSpatFlt.Geometry = pTopOp.Buffer(10); // 10 map unit buffer..

    // now let's go through layers...
    UID pFeatLayerUID = new UIDClass();
    pFeatLayerUID.Value = "{40A9E885-5533-11d0-98BE-00805F7CED21}"; // refer http://help.arcgis.com/EN/sdk/10.0/ArcObjects_NET/componenthelp/index.html#/Layers_Property/001200000m9t000000/
    IEnumLayer pEnumLayer = pMap.get_Layers(pFeatLayerUID, true);
    ILayer pThisLayer = pEnumLayer.Next();
    do
    {
        if (pThisLayer.Valid)
        {
            // this feature layer isn't broken
            // remembering that we only got feature layers in this enum
            // so it's safe (now) to do this
            IFeatureLayer pThisFeatLayer = pThisLayer as IFeatureLayer;
            IFeatureCursor pFtCur = pThisFeatLayer.Search(pSpatFlt, true); // recycling is true because we're not using the shape
            IFeature pFt = pFtCur.NextFeature(); // only the first feature, if there's anything else in proximity it is ignored

            // try to find out what field this layer has (if any) that you're interested in
            // but you could just as easy to something like
            // if (pThisLayer.Name.ToUpper() == "DIRECTOR_LAYER") for example
            if (pThisFeatLayer.FeatureClass.FindField(director) > 0)
            {
                // must be the feature class that has the director field                        
                if (pFt != null)
                {
                    // there's at least one feature in this selection
                    // get_Value returns an object..
                    object pValue = pFt.get_Value(pThisFeatLayer.FeatureClass.FindField(director));
                    if (pValue == null)
                    {
                        pdirectorValue = "<no value>";
                    }
                    else
                    {
                        pdirectorValue = pValue.ToString();
                    }
                }
                else
                    pdirectorValue = "<No feature found>";
            }
            else if (pThisFeatLayer.FeatureClass.FindField(city) > 0)
            {
                // must be the feature class that has the city field
                if (pFt != null)
                {
                    // there's at least one feature in this selection
                    object pValue = pFt.get_Value(pThisFeatLayer.FeatureClass.FindField(director));
                    if (pValue == null)
                    {
                        pcityValue = "<no value>";
                    }
                    else
                    {
                        pcityValue = pValue.ToString();
                    }
                }
                else
                    pcityValue = "<No feature found>";
            }

        }

        pThisLayer = pEnumLayer.Next();
    } while (pThisLayer != null);
}
  • Thanks a ton, that worked out well. I had an issue with the ITopologicalOperator3 type but ITopologicalOperator seemed to work out fine. For those that are looking for similar answers, some of this code needed altering but wasn't difficult - ex. I needed to look for a feature layer instead of a field. Thanks again, Michael! – Surfinsanta Sep 23 '15 at 17:19
  • Of course... I copy/pasted from another program that did use the ITopologicalOperator3 but it can't be that one as it's not implemented for points. As this has answered your question please mark this answer as accepted to show future users that it has helped you. – Michael Stimson Sep 23 '15 at 21:34
0

From this sdk sample you could use the FindFeatureLayer to get specific feature classes and then the FindFeatures to get the features at a point.

You should then have a feature cursor's per feature class and be able to go through those and get the values from their fields as needed.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.