0

I am trying to write an ArcMap (10.3) Add-In in C# .NET that will convert labels to annotation. I have used a majority of the code from the relevant snippet on the ESRI resources website. When I run the code ArcMap just crashes.

I am running:

  • Visual Studio 2012
  • Developer Kit 10.3
  • ArcMap 10.3 (Advanced license level)

Also, I have intermediate experience with Python and ArcPy, but this is my first attempt at using my novice C# skills with ArcMap, so beware of my code.

Here is my code:

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using ESRI.ArcGIS.ArcMapUI;
using ESRI.ArcGIS.Carto;
using ESRI.ArcGIS.esriSystem;
using ESRI.ArcGIS.Geodatabase;


namespace ConvertLabelsToAnnotation
{
    public class labelToAnno : ESRI.ArcGIS.Desktop.AddIns.Button
    {
        public labelToAnno()
        {
        }

        protected override void OnClick()
        {
            IMxDocument mxdoc = ArcMap.Application.Document as IMxDocument;
            IMap pMap = mxdoc.FocusMap as IMap;
            bool featureLinked = true;
            IConvertLabelsToAnnotation pConvertLabelsToAnnotation = new
                ConvertLabelsToAnnotationClass();
            ITrackCancel pTrackCancel = new TrackCancel();

            pConvertLabelsToAnnotation.Initialize(pMap,
                esriAnnotationStorageType.esriDatabaseAnnotation,
                esriLabelWhichFeatures.esriAllFeatures, true, pTrackCancel);

            IEnumLayer pEnumLayer1 = pMap.Layers;
            ILayer pLayer;
            pLayer = pEnumLayer1.Next();


            IAnnotateLayerProperties pAnnotateLayerProperties = new LabelEngineLayerPropertiesClass();
            IFeatureLayer pFeatLayer = pLayer as IFeatureLayer;
            pAnnotateLayerProperties.FeatureLayer = pFeatLayer;
            pAnnotateLayerProperties.DisplayAnnotation = false;

            IGeoFeatureLayer pGeoFeatureLayer = pLayer as IGeoFeatureLayer;
            if (pGeoFeatureLayer != null)
            {
                IFeatureClass pFeatureClass = pGeoFeatureLayer.FeatureClass;

                IDataset pDataset = pFeatureClass as IDataset;

                IFeatureWorkspace pFeatureWorkspace = pDataset.Workspace as
                    IFeatureWorkspace;

                pConvertLabelsToAnnotation.AddFeatureLayer(pGeoFeatureLayer,
                    pGeoFeatureLayer.Name + "_Anno", pFeatureWorkspace,
                    pFeatureClass.FeatureDataset, featureLinked, false, false, true, true, 
                    "");

                //Do the conversion.
                pConvertLabelsToAnnotation.ConvertLabels();
                IEnumLayer pEnumLayer = pConvertLabelsToAnnotation.AnnoLayers;
                //Turn off labeling for the layer converted.
                pGeoFeatureLayer.DisplayAnnotation = false;

                //Add the result annotation layer to the map.
                pMap.AddLayers(pEnumLayer, true);

                //Refresh the map to update the display.
                IActiveView pActiveView = pMap as IActiveView;
                pActiveView.Refresh();
            }
        }
        protected override void OnUpdate()
        {
            Enabled = ArcMap.Application != null;
        }
    }

}

I am struggling to see where I have gone wrong. Perhaps some more experienced eyes can suggest something. One thing that did come to mind is that the anno feature classes aren't being put into a gdb, at least as far as I can tell.

1

Since you say you have some experience in Python, I believe what you are trying to do could be accomplished with a Python Add-In (I'm not well versed in ArcObjects and C#). I have a jankety workaround function that I call in other scripts that will generate annotation feature classes (always for a soils data set) based on a project boundary.

The way this works is I have a dummy mxd and file geodatabase set up on one of our NAS boxes where I replace the feature class in the gdb which the mxd is sourced to. I then use the Tiled Labels to Annotation tool to pass in a project boundary and an annotation feature class is created within that boundary.

So you could create a Python Add-In with two comboboxes (one with the layer name, the other that has a field list dropdown once a layer has been chosen) and a button to create annotation from that layer. As for the boundary extent, you can create a Polygon from either the data frame extent or the extent of that layer's datasource. Here is the function I use that could be modified and called in a Python Add-In:

import arcpy, os, time
from arcpy import mapping as m
arcpy.env.overwriteOutput = True

def CreateAnnotationFC(in_fc, soils):
    gdb = r'\\Ns0113x1g2737\gis\SWPPP\_County_MN\Geodatabase\Annotation.gdb'
    arcpy.CopyFeatures_management(in_fc, os.path.join(gdb, 'Project_Boundary'))
    arcpy.CopyFeatures_management(soils, os.path.join(gdb, 'Soils'))
    time.sleep(2)  # Give it time to release schema locks
    anno_lyr = r'\\Ns0113x1g2737\gis\SWPPP\_County_MN\Geodatabase\GroupLayer.lyr'

    # delete Annotation feature class
    anno = os.path.join(gdb, 'SoilsAnno6000')
    if arcpy.Exists(anno):
        arcpy.Delete_management(anno)

    # set up mxd
    if arcpy.GetInstallInfo()['Version'] == '10.0':
        mapDoc = r'\\NS0113X1G2737\gis\SWPPP\_County_MN\MXD\SoilsTemplate_v10.mxd'
    else:
        mapDoc = r'\\NS0113X1G2737\gis\SWPPP\_County_MN\MXD\SoilsTemplate_v10_1.mxd'
    mxd = m.MapDocument(mapDoc)
    df = m.ListDataFrames(mxd)[0]
    df_name = df.name
    df.spatialReference = arcpy.Describe(in_fc).spatialReference
    for lyr in m.ListLayers(mxd,'*',df):
        if lyr.name == 'Soils':
            lyr.showLabels = True # always make sure this is on
            where = '{0} IS NOT NULL'.format(arcpy.AddFieldDelimiters(lyr.dataSource,arcpy.Describe(lyr.dataSource).OIDFieldName))
            arcpy.SelectLayerByAttribute_management(lyr,'NEW_SELECTION',where)
            df.zoomToSelectedFeatures()
            arcpy.SelectLayerByAttribute_management(lyr,'CLEAR_SELECTION',where)                          

        # Remove Group Layers  
        if lyr.isGroupLayer:
            m.RemoveLayer(df,lyr)
            arcpy.AddMessage('Removed: %s' %lyr.name)
    df.scale = 6000
    mxd.save()
    del mxd

    # Create Annotation FC
    arcpy.TiledLabelsToAnnotation_cartography(mapDoc,df_name,os.path.join(gdb,'Project_Boundary'),gdb,anno_lyr,'Anno',
                                                         6000,'','','','','','GENERATE_UNPLACED_ANNOTATION')
    arcpy.AddMessage('Created Annotation Feature Class')
    return r'\\NS0113X1G2737\gis\SWPPP\_County_MN\Geodatabase\Annotation.gdb\SoilsAnno6000'


if __name__ ==  '__main__':

    bound = r'C:\TEMP\New_Points\Swppp_input.shp'
    soils = r'C:\TEMP\SWPPP_test\SWPPP_11_06_2013\Shapefiles\All_Soils.shp'

    # test   
    CreateAnnotationFC(bound, soils)

You may also want to include another combobox where the user can type in a scale for the annotation FC.

1

So, I've solved this question myself.

The requirement was to send the annotation data to an annotation feature class within a GDB. Whilst I am yet to be able to create GDB and FCs with ArcObjects, I created these manually and then created the pointer variables that accepted the annotation data. Consequently, ArcMap did not fall over and produced the desired result.

Here is my amended code:

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using ESRI.ArcGIS.ArcMapUI;
using ESRI.ArcGIS.Carto;
using ESRI.ArcGIS.esriSystem;
using ESRI.ArcGIS.Geodatabase;
using ESRI.ArcGIS.DataSourcesGDB;
using ESRI.ArcGIS.Display;

namespace ConvertLabelsToAnnotation
{
    public class labelToAnno : ESRI.ArcGIS.Desktop.AddIns.Button
    {
        public labelToAnno()
        {
        }

        protected override void OnClick()
        {
            IMxDocument mxdoc = ArcMap.Application.Document as IMxDocument;
            IMap pMap = mxdoc.FocusMap as IMap;
            pMap.MapUnits = esriUnits.esriMeters;

            IWorkspaceFactory2 wsf = new FileGDBWorkspaceFactoryClass();

            string gdbPath = @"C:\Users\pathname";
            IWorkspace ws = wsf.OpenFromFile(gdbPath, ArcMap.Application.hWnd);

            IFeatureWorkspace fws = ws as IFeatureWorkspace;
            IFeatureClass fc = fws.OpenFeatureClass("anno");

            bool featureLinked = true;
            IConvertLabelsToAnnotation pConvertLabelsToAnnotation = new
                ConvertLabelsToAnnotationClass();
            ITrackCancel pTrackCancel = new TrackCancel();
            //Change global level options for the conversion by sending in different parameters to the next line.
            pConvertLabelsToAnnotation.Initialize(pMap,
                esriAnnotationStorageType.esriDatabaseAnnotation,
                esriLabelWhichFeatures.esriAllFeatures, true, pTrackCancel);

            //IEnumLayer pEnumLayer1 = pMap.Layers;
            IFeatureLayer pFeatLayer = new FeatureLayerClass();
            pFeatLayer.Name = "Anno_layer";
            pFeatLayer.FeatureClass = fc;
            //pLayer = pEnumLayer1.Next();


            IAnnotateLayerProperties pAnnotateLayerProperties = new LabelEngineLayerPropertiesClass();
            //IFeatureLayer pFeatLayer = pLayer as IFeatureLayer;
            pAnnotateLayerProperties.FeatureLayer = pFeatLayer;
            pAnnotateLayerProperties.DisplayAnnotation = true;

            IGeoFeatureLayer pGeoFeatureLayer = pFeatLayer as IGeoFeatureLayer;
            if (pGeoFeatureLayer != null)
            {
                IFeatureClass pFeatureClass = pGeoFeatureLayer.FeatureClass;

                IDataset pDataset = pFeatureClass as IDataset;

                IFeatureWorkspace pFeatureWorkspace = pDataset.Workspace as
                    IFeatureWorkspace;
                //Add the layer information to the converter object. Specify the parameters of the output annotation feature class here as well.
                pConvertLabelsToAnnotation.AddFeatureLayer(pFeatLayer,
                    pGeoFeatureLayer.Name + "_Anno", pFeatureWorkspace,
                    pFeatureClass.FeatureDataset, featureLinked, false, false, true, true, 
                    "");

                //Do the conversion.
                pConvertLabelsToAnnotation.ConvertLabels();
                IEnumLayer pEnumLayer = pConvertLabelsToAnnotation.AnnoLayers;
                //Turn off labeling for the layer converted.
                pGeoFeatureLayer.DisplayAnnotation = false;

                //Add the result annotation layer to the map.
                pMap.AddLayers(pEnumLayer, true);

                //Refresh the map to update the display.
                IActiveView pActiveView = pMap as IActiveView;
                pActiveView.Refresh();
            }
        }
        protected override void OnUpdate()
        {
            Enabled = ArcMap.Application != null;
        }
    }

}

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.