ProConcepts Map Exploration - EsriJapan/arcgis-pro-sdk GitHub Wiki

The mapping functionality in ArcGIS Pro is delivered through the ArcGIS.Desktop.Mapping assembly. Map Exploration provides classes and members that support navigating and interacting with views of a map. This includes modifying the view's extent by zooming to layers, features, and bookmarks, and interactively selecting or returning features that intersect a given sketch geometry.

  • ArcGIS.Desktop.Mapping.dll
  • ArcGIS.Desktop.Extensions.dll
Language:      C#
Subject:       Map Exploration
Contributor:   ArcGIS Pro SDK Team <[email protected]>
Organization:  Esri, http://www.esri.com
Date:          04/25/2025
ArcGIS Pro:    3.5
Visual Studio: 2022

In this topic

MapView

A project can contain multiple maps, either 2D or 3D, and each defines the collection of layers that make up that map. A map view is simply a view of a map. Map views are the primary interface used to display, navigate, select, identify, and edit data in a 2D or 3D map. The MapView class provides properties and methods to navigate and interact with layers in the map. The map being visualized in the view can be accessed via the Map property.

There can be multiple map views open at a given time, but there can only be one active map view. The active map view will set the context for the ribbon and many of the dock panes in the application. For example, the map Contents pane will reflect the layers of the active map view's map. The instance of the active map view can be accessed via the static Active property on MapView. The active property will return null if there is no active map view. This is useful when writing commands designed to interact with the active map.

Active Map View

Drawing mode of 3D map views can be set via the SetSceneDrawingMode method. The scene drawing mode can be either perspective or isometric. Default drawing mode is perspective and new 3D map views always open in perspective mode. Scene's field of view angle can be changed using the SetFieldOfView method.

The map view also provides the context for the selected items in the Contents pane (a.k.a. "TOC"). For example, the GetSelectedLayers method returns the collection of layers that are currently selected in the Contents pane. This context is used to determine which contextual tabs to show, for example, when one or more feature layers are selected, the Feature Layer tab group will display, and the commands will act on the selected feature layers. This is useful when writing commands to work with the selected items in the Contents pane.

Navigation

The map view's camera defines the area being displayed in the map. The camera can be accessed via the Camera property on the map view. You can set the map view's camera by using the ZoomTo(Camera) method. In addition to directly setting the camera, there are several overload methods for ZoomTo and PanTo that can be used to zoom to the extent of a layer, the definition of a bookmark, a specific geometry, and so on.

Select and identify

In some cases, you may want to provide a tool that allows the user to interactively click and sketch in the map and select or get a collection of features that intersect the sketch. The MapTool abstract class provides an easy way to author a tool that can create a sketch in the map view and return the geometry from the sketch. This geometry can then be passed into the SelectFeatures or GetFeatures method to select or return the collection of features that intersect the geometry.

Link Chart views

Starting at ArcGIS Pro 3.3, a new type of map, the "link chart" or "link chart map" is added to the public API. Link charts are displayed on link chart views. Link chart views use the MapView class; same as 2d and 3d map and scene views. Link chart maps are accessed off the MapView.Active.Map application context same as any other map type if a link chart is the current active view. To determine if a given MapView is for a link chart or not, use the MapView.IsLinkChartView property.

  //Check the active view...
  if (MapView.Active.IsLinkChartView) {
    //the current active view is a link chart...

  }

  //Find a particular link chart view amongst the open map panes
  var mapPanes = FrameworkApplication.Panes.OfType<IMapPane>().ToList();
  var mapPane = mapPanes.FirstOrDefault(
      mp => mp.MapView.IsLinkChartView && mp.MapView.Map.Name == "Acme Link Chart");
  var linkChartMap = mapPane.MapView.Map;

  //etc.

Refer to the ProConcepts Knowledge Graph for more information about Knowledge Graphs and Link Charts.

Camera

The camera serves as a tool to display the world or map, and it can be moved through space to change your view. The camera describes your active point of view, in both 2D and 3D, on the map. You can get the current camera from the view using the Camera property. You can set the camera by calling the ZoomTo(Camera) method and passing in the desired camera.

The virtual camera is your window to the map. Much like a physical camera you can manipulate in the real world, the ArcGIS Pro virtual camera is moved around to view the map (in both 2D and 3D). The movement of the camera is done in coordinates of the map or the 3D axis system (X, Y, and Z).

Camera in a 3D Scene

Viewing modes

Both 2D and 3D properties are available on the camera object. If the map view's ViewingMode is Map, you can set 2D properties. If the ViewingMode is SceneGlobal or SceneLocal, you can set 3D properties.

2D camera

In 2D, the camera defines its viewing location using X and Y. The values are in the same units as those defined by the camera’s spatial reference. This will be the center point of the 2D view’s extent. The viewing direction, or rotation, of the map is defined using the camera’s Heading property. The camera’s Scale property then defines how far the view is zoomed in or out. The value is expressed as a double representing the value on the right side of the ratio. For example, a value of 1000 is equal to a scale of 1:1000.

3D camera

In 3D, the camera defines its viewing location using X, Y, and Z. As with 2D, the values are stored in the same units as those defined by the camera’s spatial reference, with the additional possibility that XY units and Z units may be different. The viewing direction is defined by a combination of the Heading, Pitch, and Roll properties, which rotate, tilt, and roll how the camera looks at the content in the map.

Camera movement in a 3D Scene

Viewpoint

You can use a camera to define either the coordinate you're looking from (the observer) or the position that you are looking at (the target) using the Viewpoint property. If you set the Viewpoint to LookFrom, the camera viewing location will be the coordinate of the observer. If you set the Viewpoint to LookAt, the camera viewing location will be the coordinate of the target. The camera returned from the map view's Camera property will always have a Viewpoint of LookAt.

TableView

A table view is a view of a table or feature class. Table views are the primary interface for displaying, selecting and editing data in a tabular fashion. The TableView class provides properties and methods to navigate and interact with the table.

There can be multiple table views open at a given time, but there can only be one active table view. The active table view will set the context for the ribbon and the Table of Contents. The instance of the active table view can be accessed via the static Active property on TableView. The active property will return null if there is no active table view.

Table View

Typically a table view is linked to a layer or standalone table that is in a map. When visualized in this way use the MapMember property to obtain the underlying object. However, a table view can also be linked to a table or featureclass directly from an external geodatabase (ie, the table or featureclass are not in the map). In this case, the underlying object can be accessed with the Item property. Use ArcGIS.Desktop.Core.ItemFactory.CanGetDataset and ArcGIS.Desktop.Core.ItemFactory.GetDataset to retrieve the data.

Here's an example of a table view displaying data from an external source. See how the context of the Table of Contents and ribbon are different from the above picture showing table views containing map data.

External Table Views

The following snippet shows how to access the active table view.

   // get the active table view
   var activeTV = TableView.Active;   

   // get the active map member 
   var mm = activeTV.MapMember;

   // it could be a feature layer
   var fl = mm as FeatureLayer;
   // or it could be a standalone table
   var st = mm as StandaloneTable;

   // if mapMember is null, then the data has come from an external source
   // use TableView.Item
   var item = activeTV.Item;

You can set the view mode (All records or Selected records) and zoom level of the table view with the SetViewMode and SetZoomLevel methods. There are also properties to get the current ViewMode and ZoomLevel values.

   // get the active table view
   var tableView = TableView.Active;  
   // set the zoom level
   tableView.SetZoomLevel(200);

   // toggle view mode
   var vmode = tableView.ViewMode;
   tableView.SetViewMode(
      vmode == TableViewMode.eAllRecords ? TableViewMode.eSelectedRecords : TableViewMode.eAllRecords);

If you wish to show tabular data hosted on a dockpane or form, use the TableControl. All the functionalities discussed in the sections below, apply to both the TableView and TableControl.

Row Indexes and Object IDs

Access to rows in the table view is typically achieved using the row index. You can find the active row index using the ActiveRowIndex property. Navigate between rows by modifying the ActiveRowIndex property or by using the BringIntoView function which also scrolls the table view to that row. You can retrieve the object ID of a particular row by using the GetObjectIdAsync method

In many cases however, you may only know the ObjectID of the row that you wish to make current. In this case, use the GetRowIndex or GetRowIndexAsync methods to determine the row index for a given ObjectID in the dataset and then use the ActiveRowIndex or BringIntoView function to set the row.

   var tableView = TableView.Active;   
   if (tableView != null)
   {
     // get the active rowindex
     int rowIndex = tableView.ActiveRowIndex;
     // get the active OID
     long? OID = tableView.ActiveObjectId;
     long newOID = -1;

     // move to a different row
     var newIndex = 10 + rowIndex;
     await tableView.BringIntoView(newIndex);
     newOID = await tableView.GetObjectIdAsync(newIndex);


     // or move to a different row via objectID
     newOID = OID.Value + 20;
     var idx = await tableView.GetRowIndexAsync(newOID, true);
     if (idx != -1)
       await tableView.BringIntoView(idx);
  }

Selected and Highlighted Rows

Selected rows are displayed in the table view with a cyan highlight. When the table view is in Selected records view mode, you can work with a subset of the selected records by highlighting records. Highlighted records appear yellow in both the table and the map or scene view. The benefit of being able to highlight records within a selection set is that you are identifying specific features from an already defined subgroup. Note that selection is persisted but highlighting is not. That is, if you close and reopen the map, or change the selection, the highlighting is cleared, but the selection remains.

There are numerous methods to manipulate the row selection using the TableView class. You can select records by either object ID or row index using the Select method, or you can toggle the current row selection with the ToggleRowSelection method. Other options include SwitchSelection, SelectAll or ClearSelection. Each of these methods should be preceded in use by its corresponding CanXXX property (for example CanSelect, CanToggleRowSelection, CanSwitchSelection, CanClearSelection.

You can retrieve the set of selected records using either of the GetSelectedObjectIds or GetSelectedRowIndexes methods.

See the following code snippet as an example.

   var tv = TableView.Active;
   if (tv == null)
     return;

   QueuedTask.Run(async () =>
   {
      // get the set of selected objectIDs 
      var selOids = tv.GetSelectedObjectIds();
      // get the set of selected row indexes
      var selRows = tv.GetSelectedRowIndexes();

      // add to the set of selected records
      var newoids = new List<long>(selOids);
      newoids.AddRange(new List<long>() { 10, 15, 17 });
      tv.Select(newoids, true);

      // or switch the current selection
      if (tv.CanSwitchSelection)
        tv.SwitchSelection();

      // toggle the active rows selection
      if (tv.CanToggleRowSelection)
        tv.ToggleRowSelection();

      // clear the selection
      if (tv.CanClearSelection)
        tv.ClearSelection();
   });

Similar methods exist to manipulate and retrieve the highlighted records when the table view is in Selected records view mode. Retrieve the highlighted records using GetHighightedObjectIds. Use CanHighlight, Highlight, CanToggleRowHighlight, ToggleRowHighlight, CanSwitchHighlight, SwitchHighlight or CanClearHighlighted and ClearHighlighted to modify the highlighted set.

   var tv = TableView.Active;
   if (tv == null)
     return;

   QueuedTask.Run(() =>
   {
      // highlighted records are only accessible when viewMode = selected records
      if (tv.ViewMode == TableViewMode.eSelectedRecords)
      {
        // get list of current highlighted objectIDs
        var highlightedObjectIDs = tv.GetHighlightedObjectIds();

        // get list of current selected objectIDs
        var selectedObjectIds = tv.GetSelectedObjectIds();
        var idsToHighlight = new List<long>();

        // add the first two selected objectIds to highlight
        if (selectedObjectIds.Count >= 2)
        {
          idsToHighlight.Add(selectedObjectIds[0]);
          idsToHighlight.Add(selectedObjectIds[1]);
        }

        // highlight
        if (tv.CanHighlight)
          tv.Highlight(idsToHighlight, true);

        // or clear the highlight
        //if (tv.CanClearHighlighted)
        //  tv.ClearHighlighted();

        // or switch the highlight of the active row
        //if (tv.CanSwitchHighlight)
        //  tv.SwitchHighlight();
      }
    });

Once you have a set of selected or highlighted records you can zoom or pan to those records using the ZoomToSelected, PanToSelected, ZoomToHiglighted or PanToHighlighted methods. Precede each of these methods with the appropriate CanXXX property to ensure that the action is valid.

   var tv = TableView.Active;
   if (tv == null)
     return;
     
   if (tv.CanZoomToSelected)
     tv.ZoomToSelected();

Table Fields

Specific fields in the table view can be accessed by GetField or a combination of GetFieldIndex to obtain a field index followed by a GetField call (with that index). The collection of fields in the table view can be retrieved with the GetFields method.

Set the active field with the SetActiveField method using either the field index or the field name. Retrieve the active field index using ActiveFieldIndex.

The TableView class also has a number of methods and properties to allow you to alter the display by manipulating the table fields. Options include selecting fields, customize showing the field alias or field name, setting the field order, hiding fields, freezing fields (freezing fields means that the field column is aligned to the left of the table and kept visible as you scroll horizontally) or sorting the table.

See the following snippets for examples of the above actions.

   var tv = TableView.Active;
   if (tv == null)
      return;

   // field access
   var flds = tv.GetFields();
   var fldIdx = tv.GetFieldIndex("STATE_NAME");
   var fldDesc = tv.GetField(fldIdx);

   var activeIdx = tv.ActiveFieldIndex;
   tv.SetActiveField("STATE_NAME");

 
   // select a set of fields
   var selectedfields = tv.GetSelectedFields();
   tv.SetSelectedFields(new List<string> { "CITY_FIPS", "STATE_FIPS" });
   selectedfields = tv.GetSelectedFields();


   // hide fields
   tv.ShowAllFields();
   tv.SetHiddenFields(new List<string> { "CITY_FIPS", "STATE_FIPS" });
   // adds to hidden
   tv.SetHiddenFields(new List<string> { "STATE_NAME" });


   // sort fields
   var dict = new Dictionary<string, FieldSortInfo>();
   dict.Add("STATE_NAME", FieldSortInfo.Asc);
   dict.Add("CITY_NAME", FieldSortInfo.Desc);
   await tv.SortAsync(dict);


   var fields = tv.GetFields();
   tv.ResetFieldOrder();

   var fldOrder = new List<string>();
   fldOrder.Add("STATE_NAME");
   fldOrder.Add("STATE_FIPS");
   await tv.SetFieldOrderAsync(fldOrder);

ITablePane, ITablePaneEx, IExternalTablePane

As mentioned before, the table view can contain data that is either within the map or from an external source. Each view has a pane associated with it - for more information on panes see this link.

The table pane is represented by the following API interfaces; ITablePane, ITablePaneEx and IExternalTablePane depending upon the data hosted in the view.

ITablePaneEx and IExternalTablePane were introduced at 3.1, ITablePane was an existing interface which provided a few customization methods. Developers should use the ITablePaneEx and IExternalTablePane interfaces to obtain the TableView for access to the full set of table view capabilities.

   // find all the table panes (table panes hosting map data)
   var tablePanes = FrameworkApplication.Panes.OfType<ITablePane>();   
   // find all the external table panes (table panes hosting external data)
   var externalPanes = FrameworkApplication.Panes.OfType<IExternalTablePane>();

   TableView tv = null;
   var firstTablePane = tablePanes.FirstOrDefault();
   var firstExternalTablePane = externalPanes.FirstOrDefault();
   if (firstTablePane != null)
   {
     var firstTablePaneEx = firstTablePane as ITablePaneEx;
     // change the caption
     firstTablePaneEx.Caption = "My table pane";
     tv = firstTablePaneEx.TableView;
   }
   else if (firstExternalTablePane != null)
   {
     firstExternalTablePane.Caption = "My table pane";
     tv = firstExternalTablePane.TableView;
   }

   if (tv == null)
     return;

   // set the zoom level
   tv.SetZoomLevel(200);

   // set some frozen fields
   var frozenFields = tv .GetFrozenFields();
   if (!frozenFields.Contains("CITY_FIPS"))
   {
     await tv.ClearAllFrozenFieldsAsync();

     await tv.SetFrozenFieldsAsync(new List<string> { "CITY_FIPS", "STATE_FIPS" });
     // adds to frozen
     await tv.SetFrozenFieldsAsync(new List<string> { "STATE_NAME" });
   }

MapTool

ArcGIS.Desktop.Mapping.MapTool is an abstract base class that provides a basic implementation of ArcGIS.Desktop.Framework.Contracts.Tool and represents a tool command used to perform interactive operations on a MapView. It provides virtual methods that can be overridden to perform actions when keyboard and mouse events occur in the map view. It also provides properties that can be set to configure the behavior of the tool, as well as methods that wrap common functions when interacting with the view. This base class will be used to create tools to interactively identify and select features in the view as well as when creating custom construction and editing tools.

Declaring a Map Tool

Map tools are added to the <controls> section of the add-in Config.daml. Same as buttons, map tools should be referenced within the groups that will contain them and the groups are, themselves, referenced within the individual tabs on which they should be shown. They have a corresponding code file which contains the map tool "class" implementation and it should also be referenced in the tool daml. For example:

<modules>
    <insertModule id="..." ... caption="Module1">
      <tabs>
         <tab id="ProAppModule1_Tab1" caption="New Tab">
          <group refID="ProAppModule1_Group1"/><!-- reference the group here -->
        </tab>
      </tabs>
      <groups>
        <group id="ProAppModule1_Group1" caption="Group 1">
          <tool refID="ProAppModule1_MapTool1" size="large" /><!-- reference the tool in the group(s) -->
        </group>
      </groups>
      <controls>
        <!-- define the tool element -->
        <tool id="ProAppModule1_MapTool1" caption="MapTool 1" className="MapTool1" ... />
      </controls>
    </insertModule>
  </modules>

This is the map tool code:

///<summary>MapTool1 derives from the class. Note: MapTool1 is referenced in the className attribute of
///its &lt;tool&gt; element in the Config.daml</summary>
internal class MapTool1 : MapTool 
{
  public MapTool1() 
  {
    ...
  }
  ...
}

The Pro SDK includes the ArcGIS Pro Map Tool template which automates much of the daml and code class file definition required to create a basic map tool. Simply run the Pro SDK map tool template to auto-generate the tool daml and class file definition.

3MapTool.png

Using Conditions

Enabled/Disabled status of a map tool can be controlled by adding a condition attribute on the tool daml element. The condition can be:

If the condition of a tool is set to be the daml id of a pane then only when instances of that type of pane are activated will your tool be enabled. The default condition for a map tool is set by the SDK Map Tool template as condition="esri_mapping_mapPane" where esri_mapping_mapPane is the daml id for the Pro MapView pane element.

<controls>
        <!-- Enable our tool whenever a 2D or 3D map view is active. Disable it otherwise -->
        <tool id="ProAppModule1_MapTool1" ... condition="esri_mapping_mapPane">
          <tooltip .../>
        </tool>

Mouse and keyboard events

MapTool provides several virtual methods such as OnToolMouseDown and OnToolKeyDown that are called when the corresponding event occurs in the map view. By overriding these methods in the derived class, you can perform actions when these events occur. The mouse events provide event arguments that contain information such as which mouse button was used, as well as the ClientPoint, relative to the top left corner of the map view, where the event occurred. The client point can be passed into the ClientToMap method to return the corresponding location in the map. The keyboard events provide event argument that provides information such as which key was used.

These virtual methods are intended to perform synchronous operations. If you need to execute any asynchronous code, you should set the handled property on the event arguments to true. By doing this, the corresponding Handle...Async virtual method will be called with the same event arguments. For example, to perform an asynchronous operation when the left mouse button is pressed, you would do the following:

protected override void OnToolMouseDown(MapViewMouseButtonEventArgs  e)
{
  if (e.ChangedButton == System.Windows.Input.MouseButton.Left)
    e.Handled = true; //Handle the event to get the call to the async method
}

protected