I built a custom ArcGIS Pro add‑in that lets users zoom directly to any feature by typing its name. The tool adds a “Zoom Tool Tab” to the ribbon, places a “Zoom To Feature” button inside a “Zoom Tools” group, and uses C# with the ArcGIS Pro SDK. When the button is clicked the add‑in searches the active feature layer, selects the matching record, and smoothly zooms the map to its extent. The project shows my ability to extend Pro’s UI with DAML, write asynchronous map logic with the QueuedTask pattern, and package a working .esriAddInX for distribution.
<?xml version="1.0" encoding="utf-8"?>
<ArcGIS defaultAssembly="ZoomFeatureToolClean.dll"
defaultNamespace="ZoomFeatureToolClean"
xmlns="http://schemas.esri.com/DADF/Registry"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://schemas.esri.com/DADF/Registry file:///C:/Program Files/ArcGIS/Pro/bin/ArcGIS.Desktop.Framework.xsd">
<AddInInfo id="{REPLACE_GUID}"
version="1.0"
desktopVersion="3.4"
product="ArcGISPro">
<Name>Zoom Feature Tool</Name>
<Description>Zoom to a feature by name.</Description>
<Author>Jason Dutcher</Author>
<Company>Portfolio</Company>
<Date>2025‑04‑18</Date>
<Subject>Map Tools</Subject>
</AddInInfo>
<modules>
<insertModule id="ZoomFeatureToolClean_Module"
className="Module1"
autoLoad="true"
caption="Zoom Feature Tool">
<!-- ribbon tab -->
<tabs>
<tab id="ZoomFeatureToolClean_CustomTab"
caption="Zoom Tool Tab">
<group refID="ZoomFeatureToolClean_Group1"/>
</tab>
</tabs>
<!-- ribbon group -->
<groups>
<group id="ZoomFeatureToolClean_Group1"
caption="Zoom Tools"
keytip="ZT">
<button refID="ZoomFeatureToolClean_ZoomToFeatureButton"
size="large"/>
</group>
</groups>
<!-- command definition -->
<controls>
<button id="ZoomFeatureToolClean_ZoomToFeatureButton"
className="ZoomFeatureToolClean.ZoomToFeatureButton"
loadOnClick="true"
caption="Zoom To Feature"
tooltip="Zoom to a feature by name."
smallImage="Images\GenericButtonGrey16.png"
largeImage="Images\GenericButtonGrey32.png"/>
</controls>
</insertModule>
</modules>
</ArcGIS>
using System;
using System.Linq;
using ArcGIS.Desktop.Framework.Contracts;
using ArcGIS.Desktop.Framework.Dialogs;
using ArcGIS.Desktop.Mapping;
using ArcGIS.Desktop.Framework.Threading.Tasks;
using ArcGIS.Core.Data;
using ArcGIS.Desktop.Editing.Attributes;
namespace ZoomFeatureToolClean
{
internal class ZoomToFeatureButton : Button
{
protected override void OnClick()
{
QueuedTask.Run(() =>
{
string input = Microsoft.VisualBasic.Interaction.InputBox("Enter the feature name to zoom to:", "Zoom To Feature");
if (string.IsNullOrWhiteSpace(input))
return;
var featureLayer = MapView.Active.Map.GetLayersAsFlattenedList().OfType<FeatureLayer>().FirstOrDefault();
if (featureLayer == null)
{
MessageBox.Show("No feature layer found.");
return;
}
using (var table = featureLayer.GetTable())
{
var filter = new QueryFilter
{
WhereClause = $"UPPER(NAME) = UPPER('{input.Replace("'", "''")}')"
};
using (var cursor = table.Search(filter, false))
{
if (!cursor.MoveNext())
{
MessageBox.Show($"Feature '{input}' not found.");
return;
}
var row = cursor.Current;
var oid = row.GetObjectID();
featureLayer.ClearSelection();
featureLayer.Select(new QueryFilter { WhereClause = $"OBJECTID = {oid}" });
var selection = featureLayer.GetSelection();
var oidSet = selection.GetObjectIDs();
if (!oidSet.Any()) return;
var insp = new Inspector();
insp.Load(featureLayer, oidSet.First());
var extent = insp.Shape.Extent;
if (extent != null)
MapView.Active.ZoomToAsync(extent, TimeSpan.FromSeconds(1));
}
}
});
}
}
}