ProConcepts Annotation - kataya/arcgis-pro-sdk GitHub Wiki

Functionality that uses the fine-grained Annotation API. Annotation API functionality is found in ArcGIS.Core.dll. The Annotation API is commonly used in conjunction with geodatabase, map authoring, and editing.

ArcGIS.Core.dll

Language:      C#
Subject:       Annotation
Contributor:   ArcGIS Pro SDK Team <[email protected]>
Organization:  Esri, http://www.esri.com
Date:          11/24/2020
ArcGIS Pro:    2.7
Visual Studio: 2017, 2019

In this topic

Architecture

  • The ArcGIS.Core.Data.Mapping API for annotation builds upon the ArcGIS.Core.Data API and a solid understanding of ArcGIS.Core.Data API concepts is recommended.
  • Similarly to the ArcGIS.Core.Data API, the ArcGIS.Core.Data.Mapping API for annotation is a DML-only (Data Manipulation Language) API. This means that all schema creation and modification operations such as creating tables and feature classes, creating and modifying fields, enabling attachments, and so on, need to be performed using the Geoprocessing API or the user interface of ArcGIS Pro.
  • Almost all of the methods in the ArcGIS.Core.Data.Mapping API should be called on the MCT. The triple-slash documentation on the methods that need to run on the MCT are specified as such. These method calls should be wrapped inside the QueuedTask.Run call. Failure to do so will result in ConstructedOnWrongThreadException being thrown.

Annotation feature class

Annotation feature classes are collections of text features with a common set of attribute columns and class level properties. The class level properties define behavioral aspects of the feature class like editing behavior, update behavior, and assist in minimizing data size by offering a shared collection of text symbols that features may reference. In ArcGIS Pro, the annotation API is designed for use with annotation feature classes that have been upgraded to the new annotation model introduced for ArcGIS Pro.

In the ArcGIS.Core.Data.Mapping API, the AnnotationFeatureClass class inherits from the FeatureClass class. Obtaining AnnotationFeatureClass objects is similar to obtaining FeatureClass objects as shown in the following examples:

AnnotationFeatureClass annoFeatureClass = 
        geodatabase.OpenDataset<AnnotationFeatureClass>("AnnotationFeatureClassName");

In the case of a Geodatabase object representing a FeatureService, the OpenDataset can be called with the string representation of the ID for the annotation feature class.

AnnotationFeatureClass annoFeatureClass = 
                    geodatabase.OpenDataset<AnnotationFeatureClass>("1");
ArcGIS.Desktop.Mapping.Layer selectedLayer = MapView.Active.GetSelectedLayers()[0];
if (selectedLayer is ArcGIS.Desktop.Mapping.AnnotationLayer)
{
  Table table = (selectedLayer as AnnotationLayer).GetTable();

  if(table is AnnotationFeatureClass)
  {
    AnnotationFeatureClass annoFeatureClass = table as AnnotationFeatureClass;
  }
}
ArcGIS.Desktop.Editing.Events.RowChangedEvent.Subscribe(args =>
{
  Row row = args.Row;

  if(row is AnnotationFeature)
  {
    AnnotationFeatureClass annoFeatureClass = row.GetTable() as AnnotationFeatureClass;
  }
}

Opening AnnotationFeatureClass as a table

You can open a AnnotationFeatureClass object using the following code:

Table table = geodatabase.OpenDataset<Table>("FeatureClassName");

The table is an ArcGIS.Core.Data.Table reference, but in reality, it's an ArcGIS.Core.Data.Mapping.AnnotationFeatureClass object. You could cast the table reference as an AnnotationFeatureClass, and the cast would work as expected.

Opening AnnotationFeatureClass as a feature class

You can open a AnnotationFeatureClass object using the following code:

FeatureClass featureClass = geodatabase.OpenDataset<FeatureClass>("FeatureClassName");

The featureClass is an ArcGIS.Core.Data.FeatureClass reference, but in reality, it's an ArcGIS.Core.Data.Mapping.AnnotationFeatureClass object. You could cast the featureClass reference as an AnnotationFeatureClass, and the cast would work as expected.

Annotation feature class definition

Annotation feature classes have their own Definition object, AnnotationFeatureClassDefinition, which provides access to properties unique to the AnnotationFeatureClass. AnnotationFeatureClassDefinition inherits from FeatureClassDefinition to provide access to general properties of the feature class but adds the annotation specific properties. The additional annotation specific properties include reference scale, reference scale unit, general placement properties, the label class collection which defines the annotation subclasses, and the symbol collection. It also includes annotation editing options such as whether or not to automatically create new feature-linked annotation, whether or not to update annotation when the shape of a linked feature is updated, whether or not to require a symbol ID be used at all times, or whether or not symbol overrides are allowed.

AnnotationFeatureClassDefinition definition = geodatabase.GetDefinition<AnnotationFeatureClassDefinition>("AnnotationFeatureClassName");
ArcGIS.Desktop.Mapping.Layer selectedLayer = MapView.Active.GetSelectedLayers()[0];
if (selectedLayer is ArcGIS.Desktop.Mapping.AnnotationLayer)
{
  using (AnnotationFeatureClass annoFC = (selectedLayer as AnnotationLayer).GetTable())
  {
    AnnotationFeatureClassDefinition definition = annoFC.GetDefinition();
  }
}

Annotation feature

When working with an annotation feature class, the features returned via queries are of type AnnotationFeature. AnnotationFeature extends the capabilities of Feature with annotation-specific functionality. Primarily, it provides access to the CIMTextGraphic in the annotation feature. The CIMTextGraphic is the primary object that is modified when working with annotation. Additionally the AnnotationFeature provides convenience Set and Get methods for the AnnotationClassID, the LinkedFeatureID, and the annotation Status. These are simpler to update via the AnnotationFeature than via lookup of their Field index. If the annotation feature class is established with a GlobalID based relationship class, the LinkedFeatureID will be of type System.GUID, otherwise it will be a Long.

Unlike a regular Feature, the Shape of an AnnotationFeature is not routinely updated via GetShape and SetShape. Instead, the AnnotationFeature manages the shape when the CIMTextGraphic of the annotation is updated. The Shape is set to be a bounding polygon of the CIMTextGraphic.

Another concept to keep in mind when dealing with annotation is the schema. By default, annotation feature classes are created with a series of fields with descriptive information about the feature and its symbolization. While these fields are created for new feature classes, not all fields are required. In ArcGIS Pro, the only fields guaranteed to exist in an annotation schema are AnnotationClassID, SymbolID, Element, FeatureID or FeatureGlobalID (if using a GlobalID relationship), ZOrder and Status along with the system ObjectID and Shape fields. All other fields which store text formatting attributes (such as TextString, FontName, VerticalAlignment, HorizontalAlignment etc) are optional. They are not guaranteed to exist (in the physical schema). Additionally, the ArcGIS Pro annotation model no longer has Bold and Italic fields. They have been replaced with a FontStyle field. When the annotation descriptive fields exist, they are kept in sync with the contents of the CIMTextGraphic of the AnnotationFeature. Updating the CIMTextGraphic will update a field in the row corresponding to the property. Likewise, updating the field value will update the CIMTextGraphic. If you update both the field and the CIMTextGraphic in one operation and they conflict, the CIMTextGraphic will take precedence. If you are writing tools that create or modify annotation features, it is essential to take these changes and important concept into account.

Text graphic

The CIMTextGraphic is the primary object modified while manipulating an AnnotationFeature. While the AnnotationFeature API provides GetGraphic and SetGraphic methods which appear to take any CIMGraphic, only CIMGraphics of type CIMTextGraphic can be used.

There are three main properties of the CIMTextGraphic: the Text, the Shape, and the Symbol. The Text is the text string drawn by the text graphic and updates to the string are common in Annotation editing workflows. The Text string can also contain Text formatting tags for inline styling changes to the annotation. For instance, the color of a subset of characters in the string can be changed. To change the color of a single word in the middle of three words, use syntax as demonstrated below to change the word 'Special' to red.

My <CLR red="255" green="0" blue="0">Special</CLR> Text

The Shape of the CIMTextGraphic is the location the text is drawn at. This may be a MapPoint but is typically a Polyline. GeometryBag is occasionally used for text strings that have individual word placements (multi-part text). A Multipoint is used in the case where each character has a specific placement, this type is produced by the label engines when placing curved text. When updating the Text of a CIMTextGraphic with a Multipoint or GeometryBag Shape, the Geometry will be synchronized with the characters and/or words in the string to maintain data integrity.

The Symbol of a CIMTextGraphic is a CIMSymbolReference which contains the CIMTextSymbol used to draw the graphic and optionally an identifier in the SymbolName property for the symbol referenced from the symbol collection. The symbol collection is used by reference from the AnnotationFeatureClassDefinition to minimize the storage for each feature persisted. By referencing a shared symbol, the amount of repeated symbol information stored for each AnnotationFeature is reduced. However, CIMTextSymbol properties can be overridden to deviate from the referenced symbol collection symbol. The AnnotationFeature manages these overridden by comparing edits made to the CIMTextGraphic's symbol to the symbol referenced in the SymbolName property of the CIMSymbolReference. If the feature can be stored with overrides, it will be. Otherwise, the CIMTextGraphic will be disconnected from the symbol collection and the annotation feature will store the entire CIMTextSymbol. In most cases, this allows for CIMTextSymbol properties to be freely changed without worrying about storage implications. Note that AnnotationFeatureClassDefinition properties can designate that overrides are not allowed or that all symbols must reference a symbol collection symbol. If those properties are set and edits are made that violate those constraints, the edits will be rejected.

  • Opening a cursor on an AnnotationFeatureClass and making updates to the CIMTextGraphic of the AnnotationFeature is demonstrated below. Note that this example changes the text symbol height and the symbol in the symbol collection that is being referenced. The symbol ID of the symbol collection is an integer but the SymbolName property is a string, so it must be set as a string.
QueryFilter qf = new QueryFilter();
qf.WhereClause = "OBJECTID < 100";
//Note: this is a non-recycling cursor off the Table, ~not~ the layer
using (RowCursor rowCursor = featureClass.Search(qf, false))
{
  geodatabase.ApplyEdits(() =>
  {
    while (rowCursor.MoveNext())
    {
      using (AnnotationFeature annoFeat = rowCursor.Current as AnnotationFeature)
      {
        CIMTextGraphic textGraphic = annoFeat.GetGraphic() as CIMTextGraphic;
        CIMSymbolReference symbolRef = textGraphic.Symbol;
        symbolRef.SymbolName = "1";  //change the symbol being referred to by the CIMTextGraphic
        CIMTextSymbol textSymbol = symbolRef.Symbol as CIMTextSymbol;

        textSymbol.Height = 6; //change the height of the text.

        annoFeat.SetGraphic(textGraphic);
        annoFeat.Store();
      }
    }
  });
}
  • Using a RowBuffer and creating a new AnnotationFeature in an AnnotationFeatureClass is demonstrated below. The CIMTextGraphic is created and the position, text string, and CIMTextSymbol properties are specified. The text symbol from the symbol collection is referenced by ID. The symbol ID of the symbol collection is an integer but the SymbolName property is a string, so it must be set as a string. The AnnotationFeature will optimize the storage of the feature with overrides on the Store() call.
static void InsertAnno(string textString, MapPoint mapPoint, int symbolID, AnnotationFeatureClass featureClass)
{
  //Create the row buffer
  RowBuffer rowBuffer = featureClass.CreateRowBuffer();
  Feature feature = featureClass.CreateRow(rowBuffer) as Feature;

  var annoFCDef = featureClass.GetDefinition();
  var symCol = annoFCDef.GetSymbolCollection();

  //get the text symbol from the symbol collection
  var symbolIdentifier = (from s in symCol where s.ID == symbolID select s).FirstOrDefault();
  var txtSymbol = symbolIdentifier.Symbol;
  AnnotationFeature annoFeat = feature as AnnotationFeature;

  annoFeat.SetStatus(AnnotationStatus.Placed);
  annoFeat.SetAnnotationClassID(0);

  //Setup the text graphic
  CIMTextGraphic cimTextGraphic = new CIMTextGraphic();
  cimTextGraphic.Text = textString;
  cimTextGraphic.Shape = mapPoint;

  //Setup the symbol reference with the symbol id and the text symbol
  var symbolRef = new CIMSymbolReference();
  symbolRef.SymbolName = symbolID.ToString();
  symbolRef.Symbol = txtSymbol;

  //Set the symbol reference on the graphic, push it back into the feature, and store.
  cimTextGraphic.Symbol = symbolRef;
  annoFeat.SetGraphic(cimTextGraphic);
  feature.Store();
}

Additional References

The ProGuide Annotation Construction Tools and ProGuide Annotation Editing Tools give examples of building construction and editing tools for annotation. Refer to ProConcepts Editing Annotation for additional reference information relevant for annotation editing customizations.

⚠️ **GitHub.com Fallback** ⚠️