ArcObjects – Replicating ArcMap’s Point Sketch Geometry Editing with Feature Templates

arcgis-10.0arcgis-enginearcobjectseditingfeatures

I'm looking for a way to place, select, move, delete features inside a custom C# ArcObjects application (using AxMapControl). I found the exact behavior in ArcMap, but I want to save the user some steps and avoid all of the dialogs, etc. It appears to be creating a point sketch geometry.

In ArcMap, I can do the following steps:

  1. Open a new map doc
  2. Choose start editing from the Editor toolbar
  3. Then I get a dialog asking me to choose the layer to edit
  4. After selecting a layer, a panel appears that is titled "Create Features". Under it, there is another panel named "Construction Tools"
  5. When I click on a feature in the upper panel, I get a "Point" option in the lower panel
  6. Now when I move the mouse over the map, the cursor has the same icon as the feature I selected.
  7. Clicking will place a feature, then I can drag or delete.

So … how can I replicate this behavior in a custom app using ArcObjects. I've already been able to replicate the behavior of other tools by doing something like this:

ICommandPoolEdit _commandPool = new CommandPoolClass();
ICommand solveRouteToolCmd = new ControlsNetworkAnalystSolveCommand();
_commandPool.AddCommand(solveRouteToolCmd, null);

ICommand command = commandPool.get_Command((int)solveRouteToolCmd );

//pass the MapControl to the oncreate method
command.OnCreate(_axMapControl.Object);
//run the tool
command.OnClick();

However, I can't seem to find a tool class object that corresponds to this behavior. In this example ControlsNetworkAnalystSolveCommand class is the hook to the same behavior that happens when you click the solve route button in ArcMap. I'm looking for that same hook for the scenario described above.

Note that I found the tools by looking at the customize menu dialog. They are in the commands tab, in the editor category. The specific command is called Point and the description says, "Creates a point sketch geometry".

Best Answer

I haven't tested this much, but it seems to work ...

public class TestButton : ESRI.ArcGIS.Desktop.AddIns.Button
{
    public TestButton()
    {
    }

    protected override void OnClick()
    {
        try
        {
            var fLayer = StartEditing();
            if (fLayer != null)
            {
                ShowTemplate(fLayer);
                // id discovered using Categories.exe ...
                ShowDockWin("esriEditor.CreateFeatureDockWin");
            }        
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message);
        }
    }

    private static void ShowDockWin(string id)
    {
        var dockWin = GetDockWindow(id);
        if (dockWin != null)
        {
            if (!dockWin.IsVisible())
                dockWin.Show(true);
        }
    }

    private static IFeatureLayer StartEditing()
    {
        IEditor editor = ArcMap.Application.FindExtensionByName("ESRI Object Editor") as IEditor;
        IFeatureLayer fLayer = null;
        if (editor.EditState == esriEditState.esriStateNotEditing)
        {
            fLayer = ArcMap.Document.FocusMap.get_Layer(0) as IFeatureLayer;
            if (fLayer == null)
            {
                MessageBox.Show("first layer is not a featurelayer");
                return null;
            }
            editor.StartEditing(((IDataset)fLayer).Workspace);
        }
        else
            MessageBox.Show("you are already editing");
        return fLayer;
    }

    private static void ShowTemplate(IFeatureLayer fLayer)
    {
        var ed3 = ArcMap.Application.FindExtensionByName("ESRI Object Editor") as IEditor3;
        var template = FindTemplate(ed3, fLayer);
        if (template == null)
        {
            IEditTemplateFactory factory = new EditTemplateFactoryClass();
            template = factory.Create(fLayer.Name, fLayer);
            ed3.AddTemplates(ToArray(template));
        }
        if(ed3.CurrentTemplate != template)
            ed3.CurrentTemplate = template;
    }

    private static IArray ToArray(params object[] args)
    {
        IArray array = new ArrayClass();
        foreach (object o in args)
            array.Add(o);
        return array;
    }

    private static IEditTemplate FindTemplate(IEditor3 ed3, ILayer layer)
    {
        for (int i = 0; i < ed3.TemplateCount; i++)
        {
            if (ed3.get_Template(i).Layer == layer)
            {
                ed3.CurrentTemplate = ed3.get_Template(i);
                return ed3.get_Template(i);
            }
        }
        return null;
    }

    private static IDockableWindow GetDockWindow(string id)
    {
        UID uid = new UIDClass();
        try
        {
            uid.Value = id;
        }
        catch
        {
            MessageBox.Show("unable to create dockable window for " + id);
        }
        var dwm = ArcMap.Application as IDockableWindowManager;
        var dockWin = dwm.GetDockableWindow(uid);
        return dockWin;
    }

    protected override void OnUpdate()
    {
    }
}