Create a command by inheriting from BaseCommand


SummaryThis walkthrough teaches how to create a custom command by inheriting from the ESRI BaseCommand class. Inheriting the BaseCommand allows you to create commands more quickly and simple than directly implementing the ICommand interface in ESRI.ArcGIS.SystemUI.

This command will zoom the extent of the selected layer.

Click here to get the sample associated with this walkthrough.

Development licensing Deployment licensing
ArcView ArcView
ArcEditor ArcEditor
ArcInfo ArcInfo

This walkthrough takes you through the steps to create a simple command that zooms the extent of the selected layer. This command is written by inheriting from the ESRI BaseCommand class available in the ADF assembly. It includes the following steps:
 
  1. Create a new class library
  2. Add references
  3. Create a ZoomToLayer command
  4. Change the default icon bitmap
  5. Inherit the BaseCommand abstract class
  6. Add code to the overridden constructor of BaseCommand
  7. Add the ZoomToLayer functionality
  8. Expose the ZoomToLayer class to COM
  9. Compile the project
  10. Use the command in ArcMap
  11. Debugging the command
  12. Deploying the command
 

Create a new class library

 
  1. Open Visual Studio 2005.
  2. Click File, then New, and select Project.
To complete this scenario you can use either C# or VB.NET. The code for both is shown, and the full solutions for both languages are included in the associated sample. However, this document only shows the C# dialogs and screen shots since the dialogs and views you interact with in VB.NET are very similar. 
  1. In the New Project dialog box select either Visual C# or Visual Basic Projects in the left-hand pane, expand the ArcGIS section, and then click on Desktop.
Depending on whether you selected C# or VB.NET as your main language when you installed Visual Studio, the other language will be in the Other Languages section in the Project types pane.
  1. Select the Class Library (ArcMap) template in the right-hand pane.
  2. Name the project CommandInheritingBaseCommand and browse to the location you wish to save the project.
 
 
  1. Click OK and the new project will be created for you.
If the box Create directory for solution is checked, Visual Studio will create a subdirectory of the selected directory to store your project files. The name of the new directory will be the project name you specified.

Add references

 
You will need to add references to the ESRI object libraries to your C# project, as well as referencing System.Drawing.
 
In VB 6 or VC++ ArcObjects projects you add a reference to the ESRI object libraries which contains information about COM objects. Although .NET cannot use COM objects directly, the COM interoperability services provided by the .NET framework allow you to use COM objects in your .NET project. Using the tools available in Visual Studio 2005, you can create a runtime callable wrapper which allows a .NET component to create and call methods on a COM object. However, ESRI provides .NET runtime callable wrappers for you, and you will use them to instantiate and make calls on the objects in the ESRI object libraries from your .NET project.
 
ESRI also provides the ESRI.ArcGIS.ADF assembly which will be used in this walkthrough. It contains the ESRI.ArcGIS.ADF.BaseClasses namespace, which provides abstract classes you inherit from to help create a command or tool. It also contains the ESRI.ArcGIS.ADF.CATIDs namespace which contains classes to help you register your components to ESRI component categories.
 
  1. As part of the new ArcGIS Visual Studio Integration Framework features, the ArcGIS Project Wizard walks you through adding in references to .NET assemblies. This dialog will appear after you click OK from the new project dialog above. Although there are other formats for viewing the available ESRI references, here we will use the default 'Filter by: Product Features' view.
 
 
  1. Since we are creating a Desktop application, only Assemblies relevant for ArcGIS Desktop will be displayed. Expand the plus (+) sign next to Desktop ArcMap and select the following assemblies: ESRI.ArcGIS.ADF, ESRI.ArcGIS.ArcMapUI, ESRI.ArcGIS.Carto, ESRI.ArcGIS.Framework, ESRI.ArcGIS.Geometry, ESRI.ArcGIS.System and  ESRI.ArcGIS.SystemUI. To select multiple items at once, hold down the Ctrl key while you click on each item you want to select. Click Add to have your references appear in the Selected Assemblies pane.
 
 
  1. Click finish, and your project will be created.
  2. You still need a reference to System.Drawing, so click the Project menu and click Add Reference and select the .NET tab, and select the System.Drawing assembly.
 
 
  1. Click OK to dismiss the dialog box and add the assembly reference.
Recently added references can be seen by clicking the Recent tab in the Add Reference dialog.

Delete the Class1 file

 
When your project is created, a class1 file (either .cs or .vb depending on the language you chose) is added to your project by default. In our walkthrough we will not use it. Right click on that file in the Solution Explorer and choose Delete. Select OK to deleting it permanently.
 

Create a ZoomToLayer command

 
You will use one of the ArcGIS item templates to add a new class for the ZoomToLayerCommand to your project.
 
  1. In the Solution Explorer, right-click the project, Click Add, then click Add New Item.
  2. In the Add New Item dialog box, select and expand the project items and highlight ArcGIS in the Categories pane. Then select Base Command from the Templates pane. Name the class ZoomToLayer.cs (C#) or ZoomToLayer.vb (VB.NET) and click the Add button.
 
 
  1. When the ArcGIS New Item Wizard Options dialog opens, choose Desktop ArcMap Command and click OK.
 
 

Change the default icon bitmap

 
By default a bitmap is added to your project that will serve as the icon you click on in ArcMap to use your custom command. You can customize what bitmap is used with the image editor. Here you will add an existing bitmap file to your project and later you will use this file to set the icon used for the ZoomToLayer command’s button face.
 
  1. In the Solution Explorer window right click on the ZoomToLayer.bmp, choose delete and click OK to deleting the ZoomToLayer.bmp permanently.
  2. In the Solution Explorer window, right-click the project CommandInheritingBaseCommand, click Add, then click Add Existing Item.
  3. In the Add Existing Item dialog click the Files of type pull down and select Image Files.
  4. Browse to the Bin\Icons directory of your ArcGIS install, select layer_6.bmp, and click Add to copy it to your project directory.
 
 
  1. In the Solution Explorer window, make sure you've selected the new bitmap, and in the Properties window below change the Build Action property to Embedded Resource and the name to ZoomToLayer.bmp.
 
 
The icon file is now in place and ready for use later in this walkthrough.
 

Inherit the BaseCommand abstract class

 
The next step in writing the custom command is to set our ZoomToLayer class to inherit from the BaseCommand abstract class.
 
Abstract classes are classes that cannot be instantiated and are frequently either partially implemented or not implemented at all. They are closely related to interfaces; however, they differ significantly from interfaces in that a class may implement any number of interfaces, but it can inherit from only one abstract class.
 
As part of the new ArcGIS Visual Studio Integration Framework features, when you use the Add Item templates for a Desktop ArcMap Command most of the plumbing code is done for you. You automatically get the a member variable declared for the IApplication interface, the constructor is set up with stub code, the overridden OnCreate method with the application hook is created and the overridden OnClick method is stubbed out. Notice in particular how the class is set to inherit from BaseCommand:

[C#]
public sealed class ZoomToLayer : BaseCommand

[VB.NET]
Public NotInheritable Class ZoomToLayer
  Inherits BaseCommand
By convention member variables are declared at the beginning of the class definition, although the declarations can be placed anywhere within a class. Member variables of a class are often referred to as class fields in .NET.
In order to be able to use the VB.NET and C# commands in ArcMap at the same time, the ProgID of the commands has been updated to include a language specifier.
[C#]
[ProgId("CommandInheritingBaseCommand.ZoomToLayer")]

[VB.NET]
<ComClass(ZoomToLayer.ClassId, ZoomToLayer.InterfaceId, ZoomToLayer.EventsId), _
ProgId("CommandInheritingBaseCommand.ZoomToLayer")>

Add code to the constructor of BaseCommand

 
Your class now inherits from BaseCommand. You will start adding code to the plumbing code that has been added for you.
 
  1. Scroll in the code window to find the constructor for the ZoomToLayer class in the ZoomToLayer file. Notice that all the properties are empty strings, and update their values for this command as shown in the code below.
 

[C#]
public ZoomToLayer()
{
//
// TODO: Define values for the public properties
//
base.m_category = "Developer Samples"; //localizable text
base.m_caption = "Zoom To Layer CSharp"; //localizable text
base.m_message = "Zoom to the extent of the active layer in the TOC"; //localizable text 
base.m_toolTip = "Zoom To Layer CSharp"; //localizable text 
base.m_name = "DeveloperSamples_ZoomToLayerCSharp"; //unique id, non-localizable (e.g. "MyCategory_ArcMapCommand")
try
{
//
// TODO: change bitmap name if necessary
//
string bitmapResourceName = GetType().Name + ".bmp";
base.m_bitmap = new Bitmap(GetType(), bitmapResourceName);
}
catch (Exception ex)
{
System.Diagnostics.Trace.WriteLine(ex.Message, "Invalid Bitmap");
}
}

[VB.NET]
' A creatable COM class must have a Public Sub New() 
' with no parameters, otherwise, the class will not be 
' registered in the COM registry and cannot be created 
' via CreateObject.
Public Sub New()
MyBase.New()
' TODO: Define values for the public properties
MyBase.m_category = "Developer Samples" 'localizable text 
MyBase.m_caption = "Zoom To Layer VBNet" 'localizable text 
MyBase.m_message = "Zoom to the extent of the active layer in the TOC" 'localizable text 
MyBase.m_toolTip = "Zoom To Layer VBNet" 'localizable text 
MyBase.m_name = "DeveloperSamples_ZoomToLayerVBNet" 'unique id, non-localizable (e.g. "MyCategory_ArcMapCommand")
Try
'TODO: change bitmap name if necessary
Dim bitmapResourceName As String = Me.GetType().Name + ".bmp"
MyBase.m_bitmap = New Bitmap(Me.GetType(), bitmapResourceName)
Catch ex As Exception
System.Diagnostics.Trace.WriteLine(ex.Message, "Invalid Bitmap")
End Try

End Sub
  1. Since you have named your bitmap the same as the name of the class, the bitmap section placed there by the IDE integration will use the bitmap you have added.
  • The class constructor is a method that is called when the class is created. You can use it to set up members of the class. In VB.NET the constructor is named New, while in C# its name matches that of the class.

Add the ZoomToLayer functionality

 
Another new feature of the ArcGIS Visual Studio Integration Framework is ArcGIS Snippets. ArcGIS Snippets are chunks of ArcObject reusable code that can be inserted directly into your code. You can access ArcGIS Snippets by right clicking in the code window at the desired insertion point, choosing Insert Snippets : ArcGIS Desktop > from the context menu, scrolling through the desired snippets and double clicking upon one that meets your needs.
 
  1. Insert the ArcGIS Desktop > Mapping >'Zoom to Active Layer in TOC' snippet just above the end of the ZoomToLayer class.
 
 
This will add the following code:

[C#]
#region "Zoom to Active Layer in TOC"
// ArcGIS Snippet Title: 
// Zoom to Active Layer in TOC
//
// Add the following references to the project:
// ESRI.ArcGIS.ArcMapUI
// ESRI.ArcGIS.Carto
// ESRI.ArcGIS.Geometry
// 
// Intended ArcGIS Products for this snippet:
// ArcGIS Desktop
//
// Required ArcGIS Extensions:
// (NONE)
//
// Notes:
// This snippet is intended to be inserted at the base level of a Class.
// It is not intended to be nested within an existing Method.
//
// Use the following XML documentation comments to use this snippet:
/// <summary>Zooms to the selected layer in the TOC associated with the active view.</summary>
///
/// <param name="mxDocument">An IMxDocument interface</param>
/// 
/// <remarks></remarks>
public void ZoomToLayerInTOC(ESRI.ArcGIS.ArcMapUI.IMxDocument mxDocument)
{
    if (mxDocument == null)
    {
        return;
    }
    ESRI.ArcGIS.Carto.IActiveView activeView = mxDocument.ActiveView;

    // Get the TOC
    ESRI.ArcGIS.ArcMapUI.IContentsView IContentsView = mxDocument.CurrentContentsView;

    // Get the selected layer
    System.Object selectedItem = IContentsView.SelectedItem;
    if (!(selectedItem is ESRI.ArcGIS.Carto.ILayer))
    {
        return;
    }
    ESRI.ArcGIS.Carto.ILayer layer = selectedItem as ESRI.ArcGIS.Carto.ILayer;

    // Zoom to the extent of the layer and refresh the map
    activeView.Extent = layer.AreaOfInterest;
    activeView.Refresh();
}
#endregion

[VB.NET]
#Region "Zoom to Active Layer in TOC"
  ' ArcGIS Snippet Title: 
  ' Zoom to Active Layer in TOC
  '
  ' Add the following references to the project:
  ' ESRI.ArcGIS.ArcMapUI
  ' ESRI.ArcGIS.Carto
  ' ESRI.ArcGIS.Geometry
  ' 
  ' Intended ArcGIS Products for this snippet:
  ' ArcGIS Desktop
  '
  ' Required ArcGIS Extensions:
  ' (NONE)
  '
  ' Notes:
  ' This snippet is intended to be inserted at the base level of a Class.
  ' It is not intended to be nested within an existing Sub or Function.
  '
  ' Use the following XML documentation comments to use this snippet:
  ''' <summary>Zooms to the selected layer in the TOC associated with the active view.</summary>
  '''
  ''' <param name="mxDocument">An IMxDocument interface</param>
  ''' 
  ''' <remarks></remarks>
  Public Sub ZoomToLayerInTOC(ByVal mxDocument As ESRI.ArcGIS.ArcMapUI.IMxDocument)
  
    If mxDocument Is Nothing Then
      Return
    End If

    ' Get the map
    Dim activeView As ESRI.ArcGIS.Carto.IActiveView = mxDocument.ActiveView

    ' Get the TOC
    Dim contentsView As ESRI.ArcGIS.ArcMapUI.IContentsView = mxDocument.CurrentContentsView

    ' Get the selected layer
    Dim selectedItem As System.Object = contentsView.SelectedItem
    If Not (TypeOf selectedItem Is ESRI.ArcGIS.Carto.ILayer) Then
      Return
    End If

    Dim layer As ESRI.ArcGIS.Carto.ILayer = TryCast(selectedItem, ESRI.ArcGIS.Carto.ILayer) ' Dynamic Cast

    ' Zoom to the extent of the layer and refresh the map
    activeView.Extent = layer.AreaOfInterest
    activeView.Refresh()

  End Sub
#End Region
You can collapse the entire ArcGIS Snippet by clicking on the plus (+) button by '#region Zoom to Active Layer in TOC'. The functionality is still there, it just hides the lines of code in that region, making the file easier to read when you have large amounts of code in it.
  1. In order to take advantage of the functionality of the 'Zoom to Active Layer in TOC' ArcGIS Snippet you need to call the function, supplying the appropriate input parameter. The parameter required is an ESRI.ArcGIS.ArcMapUI.IMxDocument interface, and you can use another of the ArcGIS Snippets to get the MxDocument to pass in. This time insert the ArcGIS Desktop > Mapping > Map Documents > Get MxDocument from ArcMap snippet just above the end of the ZoomToLayer class.
 
 
This will add the following code:

[C#]
#region "Get MxDocument from ArcMap"
// ArcGIS Snippet Title: 
// Get MxDocument from ArcMap
//
// Add the following references to the project:
// ESRI.ArcGIS.ArcMapUI
// ESRI.ArcGIS.Framework
// ESRI.ArcGIS.System
// 
// Intended ArcGIS Products for this snippet:
// ArcGIS Desktop
//
// Required ArcGIS Extensions:
// (NONE)
//
// Notes:
// This snippet is intended to be inserted at the base level of a Class.
// It is not intended to be nested within an existing Method.
//
// Use the following XML documentation comments to use this snippet:
/// <summary>Get MxDocument from ArcMap.</summary>
///
/// <param name="application">An IApplication interface that is the ArcMap application.</param>
/// 
/// <returns>An IMxDocument interface.</returns>
/// 
/// <remarks></remarks>
public ESRI.ArcGIS.ArcMapUI.IMxDocument GetMxDocument(ESRI.ArcGIS.Framework.IApplication application)
{

    if (application == null)
    {
        return null;
    }
    ESRI.ArcGIS.ArcMapUI.IMxDocument mxDocument = ((ESRI.ArcGIS.ArcMapUI.IMxDocument)(application.Document)); // Explicit Cast

    return mxDocument;

}
#endregion 

[VB.NET]
#Region "Get MxDocument from ArcMap"
  ' ArcGIS Snippet Title: 
  ' Get MxDocument from ArcMap
  '
  ' Add the following references to the project:
  ' ESRI.ArcGIS.ArcMapUI
  ' ESRI.ArcGIS.Framework
  ' ESRI.ArcGIS.System
  ' 
  ' Intended ArcGIS Products for this snippet:
  ' ArcGIS Desktop
  '
  ' Required ArcGIS Extensions:
  ' (NONE)
  '
  ' Notes:
  ' This snippet is intended to be inserted at the base level of a Class.
  ' It is not intended to be nested within an existing Sub or Function.
  '
  ' Use the following XML documentation comments to use this snippet:
  ''' <summary>Get MxDocument from ArcMap.</summary>
  '''
  ''' <param name="application">An IApplication interface that is the ArcMap application.</param>
  ''' 
  ''' <returns>An IMxDocument interface.</returns>
  ''' 
  ''' <remarks></remarks>
  Public Function GetMxDocument(ByVal application As ESRI.ArcGIS.Framework.IApplication) As ESRI.ArcGIS.ArcMapUI.IMxDocument
  
    If application Is Nothing Then
      Return Nothing
    End If

    Dim mxDocument As ESRI.ArcGIS.ArcMapUI.IMxDocument = (CType(application.Document, ESRI.ArcGIS.ArcMapUI.IMxDocument)) ' Explicit Cast

    Return mxDocument

  End Function
#End Region
  1. Now that the snippets are in place they need to be called from the OnClick method, so that the code is executed when the custom command is clicked in ArcMap. To call the GetMxDocument method you need to pass in an ESRI.ArcGIS.Framework.IApplication interface, which was specified earlier as member variable m_application. To call the ZoomToLayerInTOC method you need to pass in an ESRI.ArcGIS.ArcMapUI.IMxDocument interface that is the return value from the GetMxDocument method. You will call both snippets in order as shown:
The OnClick function is in the Overriden Class Methods region. You may need to expand that region by clicking on the plus (+) in order to see the method.

[C#]
/// <summary>
/// Occurs when this command is clicked
/// </summary>
public override void OnClick()
{
IMxDocument mxDocument = GetMxDocument(m_application);

ZoomToLayerInTOC(mxDocument);
}

[VB.NET]
Public Overrides Sub OnClick()
  Dim mxDocument As IMxDocument = GetMxDocument(m_application)
  ZoomToLayerInTOC(mxDocument)
End Sub

Expose the ZoomToLayer class to COM

 
ArcGIS expects your command class to be a COM class; therefore you must specify that the .NET class you have created is also exposed as a COM class by creating a COM callable wrapper for it. Fortunately, this was done for you by the ArcGIS item template you used earlier to create the ZoomToLayer class in your project.
If you want to explore the code for this step you can see it by expanding the 'COM Registration Functions(s)'  #Region's section of your code.

Compile the project

 
Now you are ready to build your project.
 
  1. First make sure you have saved your project and all the work you have done.
  2. Click on the Build menu and select Build Solution.
The keyboard shortcut to build your solution is Ctrl+Shift+B, or use the F6 key.
  1. Look at the Output window at the bottom of the Visual Studio .NET IDE. If your project built correctly, you should find a report stating Build succeeded.
You can also check the results of the build operation by looking in the subdirectories of your project. By default, you will build a debug version of your project. The DLL 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 sub-directory of the project directory contains temporary files used by the compiler and by Visual Studio.
  1. If you successfully followed this walkthrough, your build will succeed and you can close Visual Studio now that your custom command has been created. If for some reason your build operation did not succeed, select the Task List window to see what errors are present, correct the errors as indicated, and then close Visual Studio once you have a successful build.
If you double-click the task, the line of code causing the error will automatically be selected for you.

Use the command in ArcMap

 
You are now ready to use the custom ZoomToLayer command in ArcMap.
 
  1. Start ArcMap, and open a map document which has some data layers.
  2. Click on the Tools menu and choose Customize to open the Customize dialog box. Select Developer Samples in the Commands tab's Categories pane.
 
 
  1. In the Commands pane, select the Zoom To Layer CSharp command, and drag it on to an ArcMap toolbar. Close the Customize dialog box.
 
 
  1. Now select any layer in the TOC and click the ZoomToLayer button, The map will zoom to the extent of that layer.
 
 
 

Debugging the command

 
Running the command in debug mode allows you to step through the code when it is executed. This is especially helpful when you come across bugs in custom commands. While you shouldn't need to debug the command you have created with this walkthrough, it is important to be familiar with these steps when writing your own commands.
 
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 take you through the process of setting it. You will need to set it when you work with a project not created by the ArcGIS Visual Studio Integration Framework or if the project user file, either *.csproj.user or *.vbproj.user, gets removed (as that is where the debugging setting is stored).
 
  1. Return to the solution in the Visual Studio 2005 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 on the CommandInheritingBaseCommand project in the Solution Explorer window and select Properties.
    2. Select the Debug tab in the property page.
    3. Under Start Action 'Start external program' should be set to use ArcMap.exe in the bin folder of your ArcGIS install directory.
The 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 those files are not included with the samples. If you are trying to debug using the provided sample you will need to 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 you will need to set it to 'Start external application' and browse to ArcMap.exe.
With the default installation settings ArcMap.exe is installed in \Program Files\ArcGIS\Bin.
 
  1. Go to the code window for the ZoomToLayer file. Find the class constructor (ZoomToLayer() in C#, New in VB.NET) and set a breakpoint there. 
To set a breakpoint in the Visual Studio 2005 IDE, click in the Margin Indicator bar (the gray area on the left side of the code editor) beside the code where you want the breakpoint set.

 
 
  1. Click the Debug menu, and then click Start Debugging (or press the F5 key). Visual Studio will run ArcMap. Follow the same steps in Using the command in ArcMap section to go over the code. When the ZoomToLayer class is instantiated the debugger will switch back to Visual Studio 2005 and allow you to step through the code one line at a time with the buttons on the Debugging toolbar.
 

Deploying the command

 
Once you have created your command, you might want to let another user run it on their ArcGIS Desktop installation. To do this, you will need to deploy your command. For complete information on doing this, see Deploying in-process components (dlls).
 


See Also:

How to implement custom commands and tools
Sample: Create a command by inheriting from BaseCommand
Deploying in-process components (dlls)