[GIS] Creating Custom Layers using ArcGIS Pro SDK for .NET

arcgis-pro-sdkarcobjectsmigration

We have a Custom Extension developed for ArcMap, which includes the Creation of a Custom Layer. The Code for the Layer is similar to what you see in this Answer to Custom Layer not drawing using ArcObjects?. This has been developed in ArcObjects & C#.

I'm now evaluating migrating the Extension to ArcGIS Pro, but can't find any documentation for a Custom Layer in ArcGIS Pro. The Only thing I find is an ArcGIS Idea for Custom Layer in ArcGIS Pro.

Can we create Custom Layers using the ArcGIS Pro SDK for .NET ?

Best Answer

This is an awful situation that must be fixed by ESRI. While they hide behind the philosophy that the ArcGIS Pro SDK is a DML (Data Manipulation Language) and shouldn't change any schema properties the raw truth is that most AddIns are there to produce output in the form of tables and featureclasses.

The only way to create a table is to: 1. Create the bare-bones table using the ArcToolbox tool. 2. Add each field individually using the ArcToolbox tool.

It takes ages to run (about 3 sec to add each field) and each field addition causes the whole map to redraw!

Trying to map the inputs to what the Toolbox tool accepts is a nightmare.

The code below works but I'm not proud of it.

    public static async Task<string> CreateFeatureClass(string sFGDB, string sFCName, 
         string sGeomType, SpatialReference pProjection)
    {
        // Create a Feature Class in sFGDB. This must be done by calling the Create FeatureClass GP tool
        // and then calling the Add Field GP Tool mulitple times. Geez!
        // Create featureclass requires:
        // ******** CREATE ********
        // Workspace
        // FC Name
        // Geometry Type; E.G. "Polygon"
        // Template FC (Can be null)
        // Has M (Yes/No)
        // Has Z (Yes/No)
        // Projection SpatialReference object
        // Alias Name
        //
        string sError = "";
        string sToolPath;
        string sTablePath = sFGDB + "\\" + sFCName;
        string sProjectionString = "";

        try
        {
            sToolPath = "management.CreateFeatureClass";
            sProjectionString = pProjection.Wkt;
            var args = Geoprocessing.MakeValueArray(sFGDB, sFCName, sGeomType, null, "No", "No",
                sProjectionString);
            IGPResult result = await Geoprocessing.ExecuteToolAsync(sToolPath, args, null, null, null,
                GPExecuteToolFlags.None);

            if (result.IsFailed == true)
            {
                StringBuilder sErr = new StringBuilder();
                string sSep = "";
                foreach (IGPMessage pErr in result.ErrorMessages)
                {
                    sErr.Append(sSep + pErr.Text);
                    sSep = "\r\n";
                }
                sError = "Error: Create Table Failed\r\n" + sErr.ToString();
                return sError;
            }

            return sError;
        }
        catch (Exception ex)
        {
            System.Diagnostics.StackTrace pStack = new System.Diagnostics.StackTrace(ex, true);
            System.Diagnostics.StackFrame pFrame = pStack.GetFrame(pStack.FrameCount - 1);
            int iLineNo = pFrame.GetFileLineNumber();
            sError = "Error: CreateFeatureClass; Line: " + iLineNo + "\r\n" + ex.Message;
            return sError;
        }
    }

    public static async Task<string> addFields(string sGDB, string sFCorTable, 
        List<clsConfig.tFieldDetails> sFields)
    {
        string sError = "";
        string sToolPath;
        string sTablePath = sGDB + "\\" + sFCorTable;
        string sFieldName;
        string sFieldType;
        string sFieldLength;

        try
        {
            await ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(async () =>
            {
                using (Geodatabase geodatabase = new Geodatabase(new FileGeodatabaseConnectionPath(new Uri(sGDB))))
                using (FeatureClass pFC = geodatabase.OpenDataset<FeatureClass>(sFCorTable))
                {
                    // Add the fields
                    sToolPath = "management.AddField";
                    // ******* FIELDS ********
                    // Input Table or FC as FeatureClass or Table
                    // Field Name
                    // Field Type "TEXT", "LONG", "DOUBLE" etc
                    // Field Length (Text fields only)
                    // Precision (null for FGDB)
                    // Field Alias
                    int iFldNo = 0;
                    foreach (clsConfig.tFieldDetails pFld in sFields)
                    {
                        sFieldName = pFld.sFldName;
                        sFieldType = pFld.sFldType;
                        var args = Geoprocessing.MakeValueArray(pFC, sFieldName, "DOUBLE", 6);
                        if (sFieldType == "TEXT")
                        {
                            args = Geoprocessing.MakeValueArray(pFC, sFieldName, "TEXT", 30);
                        }

                        IGPResult result = await Geoprocessing.ExecuteToolAsync(sToolPath, args, null);

                        if (result.IsFailed == true)
                        {
                            sError = "addFields: Add field failed\r\n" + sTablePath + "\r\n" + sFieldName + "\r" +
                                "Field No " + iFldNo.ToString() + "\r\n";
                            StringBuilder sErr = new StringBuilder();
                            string sSep = "";
                            foreach (IGPMessage pEr in result.ErrorMessages)
                            {
                                sErr.Append(sSep + pEr.ErrorCode + " " + pEr.Text);
                                sSep = "\r\n";
                            }

                            sError += sErr.ToString();
                            break;
                        }
                        iFldNo++;
                    }
                }
            });


            return sError;
        }
        catch (Exception ex)
        {
            System.Diagnostics.StackTrace pStack = new System.Diagnostics.StackTrace(ex, true);
            System.Diagnostics.StackFrame pFrame = pStack.GetFrame(pStack.FrameCount - 1);
            int iLineNo = pFrame.GetFileLineNumber();
            sError = "Error: addFields; Line: " + iLineNo + "\r\n" + ex.Message;
            return sError;
        }

    }
Related Question