Create a custom tool


This document was published with and applies to ArcGIS 9.3.
A 10 version also exists.
Summary This walkthrough demonstrates how to create a custom tool by inheriting from the ESRI BaseTool class. Inheriting the BaseTool allows you to create tools faster and easier than directly implementing the required interfaces. This tool draws graphic lines on the map based upon user interaction with the mouse.

Click here to get the sample associated with this walkthrough.

Development licensing Deployment licensing
ArcView ArcView
ArcEditor ArcEditor
ArcInfo ArcInfo

In this topic


About creating a custom tool

This walkthrough takes you through the steps to create a tool that allows the user to draw graphic lines in the map. This tool is written by inheriting from the ESRI BaseTool class available in the ESRI.ArcGIS.ADF assembly.
 

Create a class library

  1. Open Visual Studio 2005.
While this walkthrough refers to and shows screen shots from Visual Studio 2005 running on Windows XP, you can also follow the steps in Visual Studio 2008 or Windows Vista. The sample associated with this walkthrough contains the solution and project files for Visual Studio 2005 and Visual Studio 2008.
  1. Click File, click New, and click Project.
To complete this scenario, use C# or VB .NET. The code for both languages is shown and the full solutions for both languages are included in the associated sample. However, this topic only shows the VB .NET dialog boxes and screen shots since the dialog boxes and views you interact with in C# are very similar.
  1. On the New Project dialog box, select Visual C# or Visual Basic under the Project types area, click the ArcGIS node, then click Desktop.
  2. Click the Class Library (ArcMap) template under the Templates area. 
  3. Name the project CustomTool and click Browse to navigate to the location where you want to save the project. See the following screen shot:

In the associated sample, the solution and project files have 2005 or 2008 appended at the end of the name indicating the Visual Studio version (Visual Studio 2005 or Visual Studio 2008).
  1. Click OK to create the new project.
If the Create directory for solution check box is selected, Visual Studio creates a subdirectory of the selected directory to store your project files. The name of the new directory will be the specified project name.

Add references

To complete this walkthrough, add the applicable references to the .NET assemblies that contain ArcObjects functionality. The first dialog box that appears after selecting the Class Library (ArcMap) template is the ArcGIS Project Wizard. Use the ArcGIS Project Wizard to add the ESRI provided .NET assemblies. At this point, ESRI assemblies will not be added to allow another feature of the Visual Studio integrated development environment (IDE)—ArcGIS item templates and ArcGIS snippet finder—to be shown. ArcGIS item templates and ArcGIS snippet finder automatically adds the necessary ESRI assemblies into the Visual Studio code editor.
Click the Recent tab on the Add Reference dialog box to view recently added references.

Delete the class1 file

When your project is created, a class1 file (either .cs or .vb depending on the selected language) is added to the project by default; however, this walkthrough will not use the file. Right-click the class1 file in the Solution Explorer, click Delete, and click OK to permanently delete the file.
 

Create a DrawGraphicLine tool

Use one of the ArcGIS item templates to add a new class for the DrawGraphicLine tool to your project.
  1. On the Solution Explorer, right-click the project, click Add, and click Add New Item.
  2. On the Add New Item dialog box, under the Categories area, click the Visual Basic Items node and click ArcGIS. Click Base Tool under the Templates area. Name the class DrawGraphicLine.cs (C#) or DrawGraphicLine.vb (VB .NET), and click Add. See the following screen shot:

  3. When the ArcGIS New Item Wizard Options dialog box appears, click Desktop ArcMap Tool, and click OK.
  4. By default, a bitmap is added to the project and will be the icon you click in ArcMap to use for your custom tool. Customize the bitmap with the image editor by double-clicking DrawGraphicLine.bmp on the Solution Explorer and use the Visual Studio tools to design your .bmp file. See the following screen shot for an example:

 

Understand and edit DrawGraphicLine class template

As part of the ArcGIS Visual Studio Integration Framework features, when you use the Add Item templates for a Desktop ArcMap tool, most of the plumbing code is done. One main goal of the DrawGraphicLine template code is to make it easy for you to add ArcObjects functionality to your application. In this section, some plumbing code will be explained in more detail with any necessary modifications (see the DrawGraphicLine.vb or DrawGraphicLine.cs code examples for details).

[C#]
public DrawGraphicLine()
{
  //
  // TODO: Define values for the public properties.
  //
  base.m_category = "Walkthroughs"; //Localizable text. 
  base.m_caption = "Draw Graphic Line"; //Localizable text. 
  base.m_message = ""; //Localizable text.
  base.m_toolTip = "Draws a graphic line in the map window of ArcMap."; 
    //Localizable text.
  base.m_name = "CustomTool_DrawGraphicLine"; 
    //Unique ID, nonlocalizable (for example, "MyCategory_ArcMapTool").
  try
  {
    //
    // TODO: If necessary, change the resource name.
    //
    string bitmapResourceName = GetType().Name + ".bmp";
    base.m_bitmap = new Bitmap(GetType(), bitmapResourceName);
    base.m_cursor = new System.Windows.Forms.Cursor(GetType(), GetType().Name +
      ".cur");
  }
  catch (Exception ex)
  {
    System.Diagnostics.Trace.WriteLine(ex.Message, "Invalid Bitmap");
  }
}

[VB.NET]
Public Sub New()
    MyBase.New()
    ' TODO: Define values for the public properties.
    MyBase.m_category = "Walkthroughs" 'Localizable text.
    MyBase.m_caption = "Draw Graphic Line" 'Localizable text.
    MyBase.m_message = "" 'Localizable text.
    MyBase.m_toolTip = "Draws a graphic line in the map window of ArcMap." 'Localizable text.
    MyBase.m_name = "CustomTool_DrawGraphicLine" 'Unique ID, nonlocalizable (for example, "MyCategory_ArcMapTool").
    
    Try
    'TODO: If necessary, change the resource name.
    Dim bitmapResourceName As String = Me.GetType().Name + ".bmp"
    MyBase.m_bitmap = New Bitmap(Me.GetType(), bitmapResourceName)
    MyBase.m_cursor = New System.Windows.Forms.Cursor(Me.GetType(), Me.GetType().Name + ".cur")
    Catch ex As Exception
    System.Diagnostics.Trace.WriteLine(ex.Message, "Invalid Bitmap")
    End Try
    
End Sub

Add ArcGIS snippets functionality to DrawGraphicLine tool template

Another new feature of the ArcGIS Visual Studio Integration Framework is ArcGIS snippets. ArcGIS snippets are chunks of ArcObjects reusable code that can be inserted into your project. Do the following to access ArcGIS snippets:
  1. Right-click the Visual Studio code editor window at the necessary insertion point.
  2. Click ArcGIS Snippet Finder to open the dialog box.
  3. In the Keyword(s) text field, type the necessary keyword or keywords.
  4. Click Search to retrieve the ArcGIS snippet results.
  5. Under the Snippets that meet criteria area, click a snippet.
  6. Click Insert Code to add the snippet code to the Visual Studio code editor window.
 
You will add three ArcGIS snippets to the DrawGraphicLine class (add these snippets to the DrawGraphicLine.vb [VB .NET] or DrawGraphicLine.cs [C#] file near the bottom of the class file).
  1. On the ArcGIS Snippet Finder, type the keywords get activeview in the Keyword(s) text field. 
  2. Click Search.
  3. Click Get ActiveView from ArcMap under the Snippets that meet criteria area.
  4. Click Insert Code. See the following screen shot and code example that will be added:



[C#]
#region "Get ActiveView from ArcMap"
///<summary>Get ActiveView from ArcMap.</summary>
///<param name="application">An IApplication interface that is the ArcMap application.</param>
///<returns>An IActiveView interface.</returns>
///<remarks></remarks>
public IActiveView GetActiveViewFromArcMap(IApplication application)
{
  if (application == null)
  {
    return null;
  }
  IMxDocument mxDocument = application.Document as IMxDocument; // Dynamic cast.
  IActiveView activeView = mxDocument.ActiveView;
  return activeView;
}

#endregion

[VB.NET]
#Region "Get ActiveView from ArcMap"
'''<summary>Get ActiveView from ArcMap</summary>
'''<param name="application">An IApplication interface that is the ArcMap application.</param>
'''<returns>An IActiveView interface.</returns>
'''<remarks></remarks>

Public Function GetActiveViewFromArcMap(ByVal application As IApplication) As IActiveView
    
    If application Is Nothing Then
        Return Nothing
    End If
    
    Dim mxDocument As IMxDocument = TryCast(application.Document, IMxDocument) ' Dynamic cast.
    Dim activeView As IActiveView = mxDocument.ActiveView
    
    Return activeView
    
End Function

#End Region
  1. On the ArcGIS Snippet Finder window, type get polyline in the Keyword(s) text field.
  2. Click Search.
  3. Click Get Polyline From Mouse Clicks on the Snippets that meet criteria area.
  4. Click Insert Code. See the following screen shot and code example that will be added:

 

[C#]
#region "Get Polyline From Mouse Clicks"
///<summary>
///Create a polyline geometry object using the RubberBand.TrackNew method when a user clicks on the map control. 
///</summary>
///<param name="activeView">
An ESRI.ArcGIS.Carto.IActiveView interface that users interact with to draw a
  polyline. <  / param > 
///<returns>An ESRI.ArcGIS.Geometry.IPolyline interface that is the polyline the user draws.</returns>
///<remarks>Double-click to end tracking the polyline.</remarks>
public IPolyline GetPolylineFromMouseClicks(IActiveView activeView)
{
  IScreenDisplay screenDisplay = activeView.ScreenDisplay;

  IRubberBand rubberBand = new RubberLineClass();
  IGeometry geometry = rubberBand.TrackNew(screenDisplay, null);

  IPolyline polyline = (IPolyline)geometry;

  return polyline;
}

#endregion

[VB.NET]
#Region "Get Polyline From Mouse Clicks"
'''<summary>
'''Create a polyline geometry object using the RubberBand.TrackNew method when a user clicks on the map control.
'''</summary>
'''<param name="activeView">An ESRI.ArcGIS.Carto.IActiveView interface that users interacts with to draw a polyline.</param>
'''<returns>An ESRI.ArcGIS.Geometry.IPolyline interface that is the polyline the user draws.</returns>
'''<remarks>Double-click to end tracking the polyline.</remarks>

Public Function GetPolylineFromMouseClicks(ByVal activeView As IActiveView) As IPolyline
    
    Dim screenDisplay As IScreenDisplay = activeView.ScreenDisplay
    
    Dim rubberBand As IRubberBand = New RubberLineClass
    Dim geometry As IGeometry = rubberBand.TrackNew(screenDisplay, Nothing)
    
    Dim polyline As IPolyline = CType(geometry, IPolyline)
    
    Return polyline
    
End Function

#End Region
  1. On the ArcGIS Snippet Finder window, type add graphic in the Keyword(s) text field.
  2. Click Search.
  3. Click Add Graphic to Map in the Snippets that meet criteria area.
  4. Click Insert Code. See the following screen shot and code example that will be added:

 

[C#]
#region "Add Graphic to Map"
///<summary>Draw a specified graphic on the map using the supplied colors.</summary>
///<param name="map">An IMap interface.</param>
///<param name="geometry">An IGeometry interface. It can be of the geometry type: esriGeometryPoint, esriGeometryPolyline, or esriGeometryPolygon.</param>
///<param name="rgbColor">An IRgbColor interface. The color to draw the geometry.</param>
///<param name="outlineRgbColor">An IRgbColor interface. Geometries with an outline will be this color.</param>
///<remarks>Calling this function will not automatically make the graphics appear in the map area. Refresh the map area after calling this function with methods, such as, IActiveView.Refresh or IActiveView.PartialRefresh.</remarks>
public void AddGraphicToMap(IMap map, IGeometry geometry, IRgbColor rgbColor,
  IRgbColor outlineRgbColor)
{
  IGraphicsContainer graphicsContainer = (IGraphicsContainer)map; 
    // Explicit cast.
  IElement element = null;

  if ((geometry.GeometryType) == esriGeometryType.esriGeometryPoint)
  {
    // Marker symbols.
    ISimpleMarkerSymbol simpleMarkerSymbol = new SimpleMarkerSymbolClass();
    simpleMarkerSymbol.Color = rgbColor;
    simpleMarkerSymbol.Outline = true;
    simpleMarkerSymbol.OutlineColor = outlineRgbColor;
    simpleMarkerSymbol.Size = 15;
    simpleMarkerSymbol.Style = esriSimpleMarkerStyle.esriSMSCircle;
    IMarkerElement markerElement = new MarkerElementClass();
    markerElement.Symbol = simpleMarkerSymbol;
    element = (IElement)markerElement; // Explicit cast.
  }
  else if ((geometry.GeometryType) == esriGeometryType.esriGeometryPolyline)
  {
    //  Line elements.
    ISimpleLineSymbol simpleLineSymbol = new SimpleLineSymbolClass();
    simpleLineSymbol.Color = rgbColor;
    simpleLineSymbol.Style = esriSimpleLineStyle.esriSLSSolid;
    simpleLineSymbol.Width = 5;
    ILineElement lineElement = new LineElementClass();
    lineElement.Symbol = simpleLineSymbol;
    element = (IElement)lineElement; // Explicit cast.
  }
  else if ((geometry.GeometryType) == esriGeometryType.esriGeometryPolygon)
  {
    // Polygon elements.
    ISimpleFillSymbol simpleFillSymbol = new SimpleFillSymbolClass();
    simpleFillSymbol.Color = rgbColor;
    simpleFillSymbol.Style = esriSimpleFillStyle.esriSFSForwardDiagonal;
    IFillShapeElement fillShapeElement = new PolygonElementClass();
    fillShapeElement.Symbol = simpleFillSymbol;
    element = (IElement)fillShapeElement; // Explicit cast.
  }

  if (!(element == null))
  {
    element.Geometry = geometry;
    graphicsContainer.AddElement(element, 0);
  }

}

#endregion

[VB.NET]
#Region "Add Graphic to Map"
'''<summary>Draw a specified graphic on the map using the supplied colors.</summary>
'''<param name="map">An IMap interface.</param>
'''<param name="geometry">An IGeometry interface. It can be of the geometry type: esriGeometryPoint, esriGeometryPolyline, or esriGeometryPolygon.</param>
'''<param name="rgbColor">An IRgbColor interface. The color to draw the geometry.</param>
'''<param name="outlineRgbColor">An IRgbColor interface. Geometries with an outline will be this color.</param>
'''<remarks></remarks>

Public Sub AddGraphicToMap(ByVal map As IMap, ByVal geometry As IGeometry, ByVal rgbColor As IRgbColor, ByVal outlineRgbColor As IRgbColor)
    
    Dim graphicsContainer As IGraphicsContainer = CType(map, IGraphicsContainer) ' Explicit cast.
    Dim element As IElement = Nothing
    
    If (geometry.GeometryType) = esriGeometryType.esriGeometryPoint Then
        
        ' Marker symbols.
        Dim simpleMarkerSymbol As ISimpleMarkerSymbol = New SimpleMarkerSymbolClass()
        simpleMarkerSymbol.Color = rgbColor
        simpleMarkerSymbol.Outline = True
        simpleMarkerSymbol.OutlineColor = outlineRgbColor
        simpleMarkerSymbol.Size = 15
        simpleMarkerSymbol.Style = esriSimpleMarkerStyle.esriSMSCircle
        Dim markerElement As IMarkerElement = New MarkerElementClass()
        markerElement.Symbol = simpleMarkerSymbol
        element = CType(markerElement, IElement) ' Explicit cast.
        
    ElseIf (geometry.GeometryType) = esriGeometryType.esriGeometryPolyline Then
        
        '  Line elements.
        Dim simpleLineSymbol As ISimpleLineSymbol = New SimpleLineSymbolClass()
        simpleLineSymbol.Color = rgbColor
        simpleLineSymbol.Style = esriSimpleLineStyle.esriSLSSolid
        simpleLineSymbol.Width = 5
        Dim lineElement As ILineElement = New LineElementClass()
        lineElement.Symbol = simpleLineSymbol
        element = CType(lineElement, IElement) ' Explicit cast.
        
    ElseIf (geometry.GeometryType) = esriGeometryType.esriGeometryPolygon Then
        
        ' Polygon elements.
        Dim simpleFillSymbol As ISimpleFillSymbol = New SimpleFillSymbolClass()
        simpleFillSymbol.Color = rgbColor
        simpleFillSymbol.Style = esriSimpleFillStyle.esriSFSForwardDiagonal
        Dim fillShapeElement As IFillShapeElement = New PolygonElementClass()
        fillShapeElement.Symbol = simpleFillSymbol
        element = CType(fillShapeElement, IElement) ' Explicit cast.
        
    End If
    
    If Not (element Is Nothing) Then
        
        element.Geometry = geometry
        graphicsContainer.AddElement(element, 0)
        
    End If
    
End Sub

#End Region

Code the OnMouseDown method

The snippets are now in place on the code editor window of the DrawGraphicLine tool and need to be called from the OnMouseDown method. This executes the code when the custom tool is active and the user clicks the map.
 
Use the following code example to tie all ArcGIS snippets together and complete the functionality of the DrawGraphicLine tool:
 

[C#]
public override void OnMouseDown(int Button, int Shift, int X, int Y)
{
  //TODO: Add DrawGraphicLine_VB.OnMouseDown implementation.

  //Get the active view from the application object (that is, hook).
  IActiveView activeView = GetActiveViewFromArcMap(m_application);

  //Get the polyline object from the user's mouse clicks.
  IPolyline polyline = GetPolylineFromMouseClicks(activeView);

  //Make a color to draw the polyline. 
  IRgbColor rgbColor = ESRI.ArcGIS.ADF.Converter.ToRGBColor(Color.FromArgb(255,
    0, 0));

  //Add the user's drawn graphics as persistent on the map.
  AddGraphicToMap(activeView.FocusMap, polyline, rgbColor, rgbColor);

  //Only redraw the portion of the active view that contains graphics. 
  activeView.PartialRefresh(esriViewDrawPhase.esriViewGraphics, null, null);
}

[VB.NET]
Public Overrides Sub OnMouseDown(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Integer, ByVal Y As Integer)
'TODO: Add DrawGraphicLine.OnMouseDown implementation.

'Get the active view from the application object (that is, hook).
Dim activeView As IActiveView = GetActiveViewFromArcMap(m_application)

'Get the polyline object from the user's mouse clicks.
Dim polyline As IPolyline = GetPolylineFromMouseClicks(activeView)

'Make a color to draw the polyline.
Dim rgbColor As IRgbColor = ESRI.ArcGIS.ADF.Converter.ToRGBColor(Color.FromArgb(255, 0, 0))

'Add the user's drawn graphics as persistent on the map.
AddGraphicToMap(activeView.FocusMap, polyline, rgbColor, rgbColor)

'Only redraw the portion of the active view that contains graphics.
activeView.PartialRefresh(esriViewDrawPhase.esriViewGraphics, Nothing, Nothing)

End Sub

Compile the project

Build your project by doing the following: 
  1. Save the project.
  2. Click the Build menu and click Build Solution. 
  3. View the output window at the bottom of the Visual Studio .NET IDE. If the project builds correctly, a report shows the build succeeded.
Check the results of the build operation by viewing the project's subdirectories. By default, build a debug version of the project. The .dll file that results from the build operation will be stored in the Bin\Debug subdirectory of your project. This directory also contains debug information (.pdb) and a type library (.tlb) file produced by the Assembly Registration tool.
 
The obj subdirectory of the project directory contains temporary files used by the compiler and by Visual Studio.
  1. If you successfully followed this walkthrough, the build succeeds and you can close Visual Studio since the custom tool has been created. If your build operation did not succeed, select the Error List window to view the errors, correct the errors as indicated, and close Visual Studio once you have a successful build.
If you double-click the error, the line of code causing the error is automatically selected.

Use the tool in ArcMap

Do the following to use the custom DrawGraphicLine tool in ArcMap:
  1. Start ArcMap and open a map document with data layers.
  2. Click the Tools menu and click Customize to open the Customize dialog box.
  3. Click the Commands tab and click Walkthroughs under the Categories area. See the following screen shot:
If you do not see your category or command, verify Register for COM Interop is checked in your Visual Studio project's properties under the Build tab, then rebuild the project.
  1. In the Commands area under the Commands tab, click Draw Graphic Line and drag it on the ArcMap GUI in the toolbar section. Close the Customize dialog box. See the following screen shot:

  2. Click the added tool on the toolbar.
  3. Click the map window, move the mouse, click again several times to draw a polyline, and double-click to finish the drawing. See the following screen shot:

  4. When you finish drawing graphics on the map, click the Select Elements tool to select the graphic and press Delete to remove the graphic. See the following screen shot:

 

Debug the tool

Running the tool in debug mode allows you to step through the code when it is executed (helpful when you receive bugs in custom tools). Even if you don't need to debug the tool created in this walkthrough, familiarize yourself with these steps.
 
When you created your project, ArcMap.exe was set as the application to use for debugging by the ArcGIS Visual Studio Integration Framework. The following steps go through the process of setting it. Set it when you work with a project that is not created by the ArcGIS Visual Studio Integration Framework, or if the project user file (*.csproj.user or *.vbproj.user) gets removed (where the debugging setting is stored).
  1. Return to the solution in the Visual Studio IDE.
  2. Verify that ArcMap.exe is set as the external program to use for debugging. This is another feature set for you by the ArcGIS project template when you create your project.
    1. Right-click the CustomTool project in the Solution Explorer window and click Properties.
    2. Click the Debug tab on the property page.
    3. Under the Start Action area, select Start external program to use ArcMap.exe in the Bin folder of your ArcGIS install directory. See the following screen shot:
Debugging preferences are not set in the associate sample files since that information is stored in the project user file (*.csproj.user or *.vbproj.user) and these files are not included with the samples. If you are trying to debug using the provided sample, set ArcMap.exe as the debug application.
 
If the project user file has been removed since you created the project, Start Action will be set to Start project. To debug, select Start external application and browse to ArcMap.exe.
 
With the default installation settings, ArcMap.exe is installed in \Program Files\ArcGIS\Bin.
  1. In the code window for the DrawGraphicLine, find the OnMouseDown method and set a breakpoint. See the following screen shot:
To set a breakpoint in the Visual Studio IDE, click the margin indicator bar (the gray area on the left side of the code editor) next to the code where you want the breakpoint set.
 
  1. Click the Debug menu and click Start Debugging (or press F5). Visual Studio runs ArcMap. When the user clicks the map area in ArcMap, the debugger returns to Visual Studio and allows you to step through the code one line at a time with the buttons on the debugging toolbar.
 

Deploy the tool

Once you have created your tool, run it on another user's ArcGIS Desktop application. To do this, deploy your tool. For more information, see Deploying in-process components (DLLs).


See Also:

How to implement custom commands and tools
Sample: Create a custom tool
Deploying in-process components (DLLs)