Skip to content

Instantly share code, notes, and snippets.

@JeffJacobson
Last active January 29, 2019 18:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JeffJacobson/e81e0ddddf086ac7f798b343feac4b53 to your computer and use it in GitHub Desktop.
Save JeffJacobson/e81e0ddddf086ac7f798b343feac4b53 to your computer and use it in GitHub Desktop.
ArcObjects extension methods
using ESRI.ArcGIS.Carto;
using ESRI.ArcGIS.esriSystem;
using ESRI.ArcGIS.Geodatabase;
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
namespace Wsdot.ArcGis.Extensions
{
public static class Extensions
{
/// <summary>
/// Converts a dictionary into a <see cref="PropertySetClass"/>.
/// </summary>
/// <typeparam name="T">The type of values the property set will contain. Set to <see cref="object"/> if it will contain multiple types.</typeparam>
/// <param name="dict">The dictionary used to populate the <see cref="IPropertySet"/></param>
/// <returns>Returns a <see cref="IPropertySet"/> containing the contents of the input dictionary.</returns>
public static IPropertySet DictToPropertySet<T>(this IDictionary<string, T> dict)
{
IPropertySet propSet = new PropertySetClass();
foreach (var kvp in dict)
{
propSet.SetProperty(kvp.Key, kvp.Value);
}
return propSet;
}
/// <summary>
/// Creates an <see cref="IEnumerable{string}"/> of the elements of a <see cref="IStringArray"/>.
/// </summary>
/// <param name="stringArray">An <see cref="IStringArray"/></param>
/// <returns>Returns an <see cref="IEnumerable{string}"/></returns>
public static IEnumerable<string> AsEnumerable(this IStringArray stringArray)
{
for (int i = 0, l = stringArray.Count; i < l; i++)
{
yield return stringArray.Element[i];
}
}
/// <summary>
/// Iterates over the objects in an <see cref="IVariantArray"/>.
/// </summary>
/// <param name="variantArray">An <see cref="IVariantArray"/></param>
/// <returns>Returns an <see cref="IEnumerable{object}"/>.</returns>
public static IEnumerable<object> AsEnumerable(this IVariantArray variantArray)
{
for (int i = 0, l = variantArray.Count; i < l; i++)
{
yield return variantArray.Element[i];
}
}
/// <summary>
/// Iterates over the objects in an <see cref="ILongArray"/>.
/// </summary>
/// <param name="longArray">
/// An ArcObjects <see cref="ILongArray"/> (which contains <see cref="int"/> values).
/// </param>
/// <returns>Returns an <see cref="IEnumerable{int}"/></returns>
public static IEnumerable<int> AsEnumerable(this ILongArray longArray)
{
for (int i = 0, l = longArray.Count; i < l; i++)
{
yield return longArray.Element[i];
}
}
/// <summary>
/// Enumerates the values returned from <see cref="ISqlWorkspace.GetColumns(string, out IStringArray, out IStringArray, out IVariantArray, out ILongArray, out ILongArray, out ILongArray)"/>.
/// </summary>
/// <param name="ppColumnName">An <see cref="IStringArray"/> containing column names</param>
/// <param name="ppColumnType">An <see cref="IStringArray"/> containing column type strings.</param>
/// <param name="ppIsNullable">An <see cref="IVariantArray"/> containing <see cref="bool"/> values.</param>
/// <param name="ppSize">An <see cref="ILongArray"/> containing <see cref="int"/>values</param>
/// <param name="ppPrecision">An <see cref="ILongArray"/> containing <see cref="int"/>values</param>
/// <param name="ppScale">An <see cref="ILongArray"/> containing <see cref="int"/>values</param>
/// <returns></returns>
public static IEnumerable<(
string columnName, string columnType, bool isNullable,
int size, int precision, int scale)> AsEnumerable(
IStringArray ppColumnName,
IStringArray ppColumnType,
IVariantArray ppIsNullable,
ILongArray ppSize,
ILongArray ppPrecision,
ILongArray ppScale)
{
for (int i = 0, l = ppColumnName.Count; i < l; i++)
{
yield return (
ppColumnName.Element[i],
ppColumnType.Element[i],
(bool)ppIsNullable.Element[i],
ppSize.Element[i],
ppPrecision.Element[i],
ppScale.Element[i]
);
}
}
/// <summary>
/// Creates a <see cref="UID"/> from the <see cref="Type.GUID"/> from an ArcObjects type.
/// </summary>
/// <param name="type">An ArcObjects type.
/// </param>
/// <returns>A <see cref="UIDClass"/></returns>
/// <example>
/// UID arcGuid = typeof(IFeatureLayer).CreateGuidForType();
/// </example>
public static UIDClass CreateGuidForType(this Type type)
{
var guid = type.GUID;
var arcGuid = new UIDClass
{
Value = $"{{{guid.ToString().ToUpper()}}}"
};
return arcGuid;
}
/// <summary>
/// Enumerates the layers of a certain type of an object implementing <see cref="IMapLayers"/>.
/// </summary>
/// <typeparam name="T">A layer type such as <see cref="IFeatureLayer"/>.</typeparam>
/// <param name="mapLayers"></param>
/// <returns></returns>
/// <example>
/// // Note: mapDoc is assumed to be an IMapDocument in this example.
/// // Loop through all of the feature layers and add relationships to each table in the view.
/// var mapLayers = (IMapLayers2)mapDoc.ActiveView;
/// var featureLayers = mapLayers.EnumerateFeatureLayers<IFeatureLayer>();
/// foreach (var fl in featureLayers)
/// {
/// // do something with the feature layer
/// Console.WriteLine($"Layer name: {fl.Name}");
/// }
/// </example>
public static IEnumerable<T> EnumerateFeatureLayers<T>(this IMapLayers mapLayers) where T: ILayer
{
var outType = typeof(T);
UID arcGuid = outType.CreateGuidForType();
var enumLayer = mapLayers.Layers[arcGuid, false];
var currentLayer = enumLayer.Next();
while (currentLayer != null)
{
if (currentLayer is T tLayer) {
yield return tLayer;
}
currentLayer = enumLayer.Next();
}
}
/// <summary>
/// Enumerates sets of <see cref="ITableFields.Field(int)"/> and <see cref="ITableFields.FieldInfo(int)"/>
/// </summary>
/// <param name="tableFields">
/// An object implementing <see cref="ITableFields"/>, such as <see cref="FeatureLayerClass"/>
/// or <see cref="StandaloneTableClass"/>.
/// </param>
/// <returns>An <see cref="IEnumerator{Tuple{IField, IFieldInfo}}"/></returns>
internal static IEnumerable<(IField, IFieldInfo)> AsEnumerable(this ITableFields tableFields)
{
for (int i = 0, l = tableFields.FieldCount; i < l; i++)
{
var field = tableFields.Field[i];
var fieldInfo = tableFields.FieldInfo[i];
yield return (field, fieldInfo);
}
}
/// <summary>
/// Enumerates over the <see cref="IStandaloneTable"/>s in an <see cref="IStandaloneTableCollection"/>.
/// </summary>
/// <param name="tableCollection">Can be cast from an <see cref="IActiveView"/>.</param>
/// <returns></returns>
public static IEnumerable<IStandaloneTable> AsEnumerable(this IStandaloneTableCollection tableCollection)
{
for (int i = 0, l = tableCollection.StandaloneTableCount; i < l; i++)
{
yield return tableCollection.StandaloneTable[i];
}
}
/// <summary>
/// Creates an alias name by splitting detecting words in the Pascal-case
/// field name and separating them with a space.
/// </summary>
/// <param name="fieldName">A Pascal-case field name string</param>
/// <returns>Returns a string containing the space separated individual words.</returns>
public static string GenerateAliasName(this string fieldName)
{
const string wordPattern = @"((SRMP)|([A-Z][a-z]+)|([A-Z]{2}?))";
var wordList = new List<string>();
var matches = Regex.Matches(fieldName, wordPattern, RegexOptions.ExplicitCapture);
foreach (Match match in matches)
{
var word = match.Value;
wordList.Add(word);
}
var output = string.Join(" ", wordList);
output = Regex.Replace(output, @"(?i)\bId\b", "ID");
output = Regex.Replace(output, @"(?i)\bDesc\b", "Description");
output = Regex.Replace(output, @"(?i)\bInd\b", "Indicator");
return output;
}
/// <summary>
/// Automatically generates field aliases for the fields in a layer or table.
/// </summary>
/// <param name="layer">
/// A class implementing <see cref="ITableFields"/>, such as <see cref="FeatureLayerClass"/>
/// or <see cref="StandaloneTableClass"/>.
/// </param>
public static void SetFieldAliases(this ITableFields layer)
{
foreach (var (field, fieldInfo) in layer.AsEnumerable())
{
var alias = field.Name.GenerateAliasName();
if (string.IsNullOrWhiteSpace(alias))
{
continue;
}
fieldInfo.Alias = field.Name.GenerateAliasName();
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment