{"id":31,"date":"2010-12-15T11:23:34","date_gmt":"2010-12-15T19:23:34","guid":{"rendered":"http:\/\/gis.qtools.com\/blog\/"},"modified":"2016-04-11T12:16:26","modified_gmt":"2016-04-11T19:16:26","slug":"part-6-converting-vba-arcobjects-to-cs","status":"publish","type":"page","link":"https:\/\/gis.qtools.com\/blog\/tutorials\/vba-to-c-add-in\/part-6-converting-vba-arcobjects-to-cs\/","title":{"rendered":"Part 6: Converting VBA ArcObjects to CS"},"content":{"rendered":"<p><strong>Tutorial Navigation<\/strong> | Previous: <a href=\"..\/part-5-adding-utility-dialog-form\/\">Part 5: Adding the Utility&#8217;s Dialog Form<\/a> | Next: <a href=\"..\/part-7-deploying-the-add-in\/\">Part 7: Deploying the Add-in<\/a><\/p>\n<p>Continuing with the Visual Studio project from Part 5, we will now perform a mostly line-by-line conversion of the ArcObjects code used by the VBA utility.<\/p>\n<p>Note: At this stage, no attempt will be made to conform to all best practices for C# coding, such as class and method extraction, and robust and specific exception handling.<\/p>\n<h1>Resources<\/h1>\n<h3>Files<\/h3>\n<p>See Part 4.<\/p>\n<h3>Video Demonstrations<\/h3>\n<p>The following videos are also linked from the relevant sections below. (opens in a new browser window or tab)<\/p>\n<p><a href=\"\/\/gis.qtools.com\/tutorials\/vba_to_cs\/video\/CS2008_ConvertVBA_Demo_pt01.swf.html\" target=\"_blank\">Paste VBA code into C# code editor<\/a> (duration 1:04)<br \/>\n<a href=\"\/\/gis.qtools.com\/tutorials\/vba_to_cs\/video\/CS2008_ConvertVBA_Demo_pt02.swf.html\" target=\"_blank\">Start converting variable declarations<\/a> (duration 0:43)<br \/>\n<a href=\"\/\/gis.qtools.com\/tutorials\/vba_to_cs\/video\/CS2008_ConvertVBA_Demo_pt03.swf.html\" target=\"_blank\">Adding references and using statements while converting<\/a> (duration 0:53)<br \/>\n<a href=\"\/\/gis.qtools.com\/tutorials\/vba_to_cs\/video\/CS2008_ConvertVBA_Demo_pt04.swf.html\" target=\"_blank\">Declaring a variable and assigning it a new object<\/a> (duration 0:35)<\/p>\n<h1>Convert the VBA Code to C#<\/h1>\n<h2>Paste the VBA code into Visual Studio<\/h2>\n<p><b>Video Demonstation:<\/b> <a href=\"\/\/gis.qtools.com\/tutorials\/vba_to_cs\/video\/CS2008_ConvertVBA_Demo_pt01.swf.html\" target=\"_blank\">Paste VBA code into C# code editor<\/a> (duration 1:04)<\/p>\n<p>During the ArcObjects VBA to C# conversion process, it is helpful to have the VBA code in the Visual Studio code editor, formatted as comments.<\/p>\n<p>We could place the operational code in the <code>OnClick()<\/code> method, but to keep that method simple and cut down on indent levels, we will create a separate method for our ArcObjects code.<\/p>\n<p>Select the <em>StaggerOffsetButton.cs <\/em>file in the code editor, locate the <code>OnClick()<\/code> method, scroll down and click to the right of the method&#8217;s closing brace, press <code>Enter<\/code> twice, and create a new method named <code>Perform<\/code>:<\/p>\n<pre lang=\"csharp\" line=\"56\">\r\nprivate void Perform()\r\n{\r\n    \/\/ Paste VBA Code here, and then comment it out.\r\n}\r\n<\/pre>\n<p>For those of you new to C#&#8230; (<a href=\"#\" onclick=\"xcollapse('X0000');return false;\">+\/-<\/a>)<\/p>\n<div id=\"X0000\" style=\"display: none; background: transparent;\">\n<p> <code>void<\/code> means the method does not return a value (it has no return type), and the empty parenthesis are required for methods that do not accept arguments.<\/p>\n<p>So in C#, methods correspond roughly to subs and functions in VB: <\/p>\n<pre lang=\"csharp\" line=\"\">\r\n\/\/ VB sub\r\nPrivate Sub Perform()\r\n\/\/ Equivalent C# method\r\nprivate void Perform()\r\n \r\n\/\/ VB function\r\nPrivate Function GetSomeValue(iSomeParam As Long) As Long\r\n\/\/ Equivalent C# method\r\nprivate int GetSomeValue(int someParam)\r\n<\/pre>\n<hr>\n<\/div>\n<p>Copy and paste the entire contents of the <em>VBA_OffsetFeatures.txt<\/em> file provided with this tutorial into the new method. Select the pasted-in code and comment it out by clicking the <em>Comment Selection<\/em> button (or <em>View | Advanced | Comment Selection<\/em>). With the commented-out VBA code still selected, press the <em>TAB<\/em> key three times to indent it correctly.<\/p>\n<p>Expand this to view the entire <code>Perform()<\/code> method after pasting in the code and commenting it out. (<a href=\"#\" onclick=\"xcollapse('X0001');return false;\">+\/-<\/a>)<\/p>\n<div id=\"X0001\" style=\"display: none; background: transparent;\">\n<pre lang=\"csharp\" line=\"56\">\r\nprivate void Perform()\r\n{\r\n    \/\/Private Sub OffsetFeatures_Click()\r\n    \/\/' Created by Jeff Hamblin\r\n    \/\/' Version: 11\/30\/2010\r\n    \/\/'\r\n    \/\/' Based on the \"Move Features\" code found on ESRI EDN website,\r\n    \/\/' which moves selected features a fixed distance.\r\n    \/\/'\r\n    \/\/' The purpose of this tool is to stagger and offset line features so\r\n    \/\/' that overlapping lines are separated and viewable.\r\n\r\n    \/\/    Dim sToolName As String\r\n    \/\/    sToolName = \"Stagger Offset Features\"\r\n\r\n    \/\/    Dim pMxDoc As IMxDocument\r\n    \/\/    Dim pLayer As ILayer\r\n    \/\/    Dim pFeatureLayer As IFeatureLayer\r\n    \/\/    Dim pCursor As IFeatureCursor\r\n        \r\n    \/\/    Dim pID As New UID\r\n    \/\/    Dim pEditor As IEditor\r\n    \/\/    Dim pFeature As IFeature\r\n    \/\/    Dim pFeatureEdit As IFeatureEdit\r\n    \/\/    Dim pLine As ILine\r\n    \/\/    Dim pMoveSet As ISet\r\n    \/\/    Dim pSpatialReference As ISpatialReference\r\n    \/\/    Dim pStartPoint As IPoint\r\n    \/\/    Dim pEndPoint As IPoint\r\n        \r\n    \/\/    Dim origX As Double\r\n    \/\/    Dim origY As Double\r\n    \/\/    Dim bInOperation As Boolean\r\n        \r\n    \/\/    Dim Dlg_Result As String\r\n    \/\/    Dim Offset_SizeX As Integer\r\n    \/\/    Dim Offset_SizeY As Integer\r\n    \/\/    Dim DistanceX As Integer\r\n    \/\/    Dim DistanceY As Integer\r\n    \/\/    Dim StaggerIndex As Integer\r\n    \/\/    Dim F_Count As Long\r\n      \r\n    \/\/    On Error GoTo ErrorHandler\r\n        \r\n    \/\/    Set pMxDoc = ThisDocument\r\n        \r\n    \/\/    Set pLayer = pMxDoc.SelectedLayer\r\n        \r\n    \/\/    ' Make sure some type of layer is selected\r\n    \/\/    If (pLayer Is Nothing) Then\r\n    \/\/        MsgBox \"Please Select a feature layer to offset\", vbOKOnly, sToolName\r\n    \/\/        Exit Sub\r\n    \/\/    End If\r\n        \r\n    \/\/    ' Make sure a feature layer (not a group layer) is selected\r\n    \/\/    If Not (TypeOf pLayer Is IFeatureLayer) Then\r\n    \/\/        MsgBox \"Please Select a feature layer\", vbOKOnly, sToolName\r\n    \/\/        Exit Sub\r\n    \/\/    End If\r\n        \r\n    \/\/    Set pFeatureLayer = pMxDoc.SelectedLayer\r\n    \/\/    Set pLayer = pFeatureLayer\r\n        \r\n    \/\/    ' Get count of features\r\n    \/\/    F_Count = pFeatureLayer.FeatureClass.FeatureCount(Nothing)\r\n        \r\n    \/\/    ' Display a form to get offset values\r\n    \/\/    form_OffsetFeatures.pPrompt.Caption = \"Move \" & F_Count & \" features in:\" & _\r\n    \/\/            vbNewLine & pFeatureLayer.Name\r\n    \/\/    form_OffsetFeatures.Show\r\n    \/\/    If form_OffsetFeatures.Canceled Then\r\n    \/\/        Exit Sub\r\n    \/\/    Else\r\n    \/\/        Offset_SizeX = form_OffsetFeatures.MoveDistX\r\n    \/\/        Offset_SizeY = form_OffsetFeatures.MoveDistY\r\n    \/\/    End If\r\n            \r\n        \r\n    \/\/    ' Get a reference to the editor extension\r\n    \/\/    pID = \"esriEditor.Editor\"\r\n    \/\/    Set pEditor = Application.FindExtensionByCLSID(pID)\r\n        \r\n    \/\/    ' Create an edit operation enabling undo for the operation\r\n    \/\/    pEditor.StartOperation\r\n    \/\/    bInOperation = True\r\n            \r\n    \/\/    Set pCursor = pFeatureLayer.FeatureClass.Update(Nothing, False)\r\n        \r\n    \/\/    Set pFeature = pCursor.NextFeature\r\n            \r\n            \r\n    \/\/    ' Cause the staggered offset to be centered on original position\r\n    \/\/    StaggerIndex = F_Count \/ -2\r\n        \r\n    \/\/    While (Not pFeature Is Nothing)\r\n            \r\n    \/\/        ' Select the feature\r\n    \/\/        pMxDoc.FocusMap.SelectFeature pLayer, pFeature\r\n            \r\n    \/\/        Set pMoveSet = New esriSystem.Set\r\n              \r\n    \/\/        pMoveSet.Add pFeature\r\n              \r\n    \/\/        ' Reset the Set\r\n    \/\/        pMoveSet.Reset\r\n              \r\n    \/\/        ' MoveSet requires a line to specify the new location\r\n    \/\/        ' Use the selection anchor as a starting point for the line\r\n    \/\/        Set pStartPoint = pEditor.SelectionAnchor.Point\r\n    \/\/        Set pLine = New Line\r\n    \/\/        pStartPoint.QueryCoords origX, origY\r\n    \/\/        Set pEndPoint = New Point\r\n            \r\n    \/\/        ' Calculate the total offset for the selection\r\n    \/\/        ' Uses linear unit of data frame PCS\r\n    \/\/        DistanceX = Offset_SizeX * StaggerIndex\r\n    \/\/        DistanceY = Offset_SizeY * StaggerIndex\r\n            \r\n    \/\/        pEndPoint.PutCoords (origX + DistanceX), (origY + DistanceY)\r\n    \/\/        pLine.PutCoords pStartPoint, pEndPoint\r\n              \r\n    \/\/        ' Get the spatial reference from the map and assign it to the new line\r\n    \/\/        Set pSpatialReference = pEditor.Map.SpatialReference\r\n    \/\/        ' Set the spatial reference of the new line\r\n    \/\/        ' Do the move while looping through the set\r\n    \/\/        Set pLine.SpatialReference = pSpatialReference\r\n    \/\/        Set pFeatureEdit = pMoveSet.Next\r\n    \/\/        Do While Not pFeatureEdit Is Nothing\r\n    \/\/          ' Move all the selected features\r\n    \/\/          pFeatureEdit.MoveSet pMoveSet, pLine\r\n    \/\/          Set pFeatureEdit = pMoveSet.Next\r\n    \/\/        Loop\r\n            \r\n    \/\/        pMoveSet.RemoveAll\r\n            \r\n    \/\/        pMxDoc.FocusMap.ClearSelection\r\n            \r\n    \/\/        Set pFeature = pCursor.NextFeature\r\n    \/\/        StaggerIndex = StaggerIndex + 1\r\n    \/\/    Wend\r\n        \r\n    \/\/    ' Stop the Edit Operation\r\n    \/\/    pEditor.StopOperation \"Move Selection\"\r\n    \/\/    bInOperation = False\r\n            \r\n    \/\/    pMxDoc.ActiveView.Refresh\r\n        \r\n    \/\/    ' Additionally move the selection anchor\r\n    \/\/    pEditor.SelectionAnchor.MoveTo pEndPoint, pEditor.Display\r\n        \r\n    \/\/    Exit Sub\r\n      \r\n    \/\/ErrorHandler:\r\n    \/\/  If bInOperation Then\r\n    \/\/    pEditor.AbortOperation\r\n    \/\/    MsgBox \"Error moving features.\"\r\n    \/\/  End If\r\n    \/\/End Sub\r\n\r\n\r\n}\r\n<\/pre>\n<hr>\n<\/div>\n<h2>Convert the variable declarations<\/h2>\n<p><b>Video Demonstation:<\/b> <a href=\"\/\/gis.qtools.com\/tutorials\/vba_to_cs\/video\/CS2008_ConvertVBA_Demo_pt02.swf.html\" target=\"_blank\">Start converting variable declarations<\/a> (duration 0:43)<\/p>\n<p>In most VBA code, variables are declared at the top of subs and functions. In C#, the convention is to declare variables on first use. To keep this tutorial as simple as possible, a line-by-line conversion will be performed, keeping variable declarations at the top before operational code.<\/p>\n<p>Variable names, however, will be changed to the C# convention of lower-case first letter and camel case, fully spelled-out names (e.g. <code>pMxDoc<\/code> -> <code>mxDocument<\/code>).<\/p>\n<p>During this process, references to assemblies and their corresponding <code>using<\/code> statements will be added as needed.<\/p>\n<p>How do I add references and using statements? (<a href=\"#\" onclick=\"xcollapse('X0002');return false;\">+\/-<\/a>)<\/p>\n<div id=\"X0002\" style=\"display: none; background: transparent;\">\n<hr>\n<p><b>Video Demonstation:<\/b> <a href=\"\/\/gis.qtools.com\/tutorials\/vba_to_cs\/video\/CS2008_ConvertVBA_Demo_pt03.swf.html\" target=\"_blank\">Adding references and using statements while converting<\/a> (duration 0:53)<\/p>\n<p>If you enter a type (e.g. <code>ILine<\/code>) and it gets a red squigly line under it, it is undefined.<\/p>\n<p><img decoding=\"async\" src=\"\/\/gis.qtools.com\/tutorials\/vba_to_cs\/images\/CS2008_ConvertVBA_01.png\" \/><\/p>\n<p>Right-click on the type name in the code editor and look for an item at the top of the context menu named <em>Resolve<\/em>, and if it is there, select the <code>using<\/code> statement on its sub-menu (e.g. <code>using ESRI.ArcGIS.Geometry;<\/code>). This inserts a new  <code>using<\/code> statement line at the top of the class file.<\/p>\n<p>If there is not a <em>Resolve<\/em> item on the context menu, then there is no reference to the required assembly yet in the project. There are several ways to find the name of the assembly and add it the project. One is to learn the name from the documentation for the object or interface, and then add its reference in the Solution Explorer. Another is to use Visual Studio&#8217;s <em>Object Browser<\/em>. Open it from <em>View | Other Windows | Object Browser<\/em>. Enter the type name (e.g. <code>ILine<\/code>) into the search box and hit search. After it locates the reference, click the button with the yellow plus symbol on the object browser&#8217;s toolbar to add the reference to the project.<\/p>\n<p><img decoding=\"async\" src=\"\/\/gis.qtools.com\/tutorials\/vba_to_cs\/images\/CS2008_ConvertVBA_02.png\" \/><br \/>\nNow right-click again on the type name in the code editor and use <em>Resolve<\/em> to add the <code>using<\/code> statement to the class file.<\/p>\n<p>A note about <code>using<\/code> statements: They are not strictly required, but are used for coding convenience and efficiency. Once an assembly reference has been added to a project, indentifiers defined within them can be used without an associated <code>using<\/code> statement as long as they are full qualified. In the example above, the <code>ILine<\/code> interface could be used in code as <code>ESRI.ArcGIS.Geometry.ILine<\/code>. You may find this in some sample code as it safeguards against name collisions in separate assemblies. However, it slows down coding and adds to visual clutter, so <code>using<\/code> statements are a generally accepted practice.<\/p>\n<hr>\n<\/div>\n<p><b>Video Demonstation:<\/b> <a href=\"\/\/gis.qtools.com\/tutorials\/vba_to_cs\/video\/CS2008_ConvertVBA_Demo_pt04.swf.html\" target=\"_blank\">Declaring a variable and assigning it a new object<\/a> (duration 0:35)<\/p>\n<p>Working in the <code>Perform()<\/code> method in the <em>StaggerOffsetButton.cs <\/em>file in the code editor.<\/p>\n<p>Following is the line-by-line conversion of the VBA code variable declarations to C#.<\/p>\n<pre lang=\"csharp\" line=\"52\">\r\n...\r\n\/\/    Dim sToolName As String\r\n\/\/    sToolName = \"Stagger Offset Features\"\r\nstring toolName = \"Stagger Offset Features\";\r\n\r\n\/\/    Dim pMxDoc As IMxDocument\r\nIMxDocument mxDocument;\r\n\r\n\/\/    Dim pLayer As ILayer\r\nILayer layer;\r\n\r\n\/\/    Dim pFeatureLayer As IFeatureLayer\r\nIFeatureLayer featureLayer;\r\n\r\n\/\/    Dim pCursor As IFeatureCursor\r\nIFeatureCursor featureCursor;\r\n    \r\n\/\/    Dim pID As New UID\r\nUID editorUID = new UIDClass();\r\n\r\n\/\/    Dim pEditor As IEditor\r\nIEditor editor;\r\n\r\n\/\/    Dim pFeature As IFeature\r\nIFeature feature;\r\n\r\n\/\/    Dim pFeatureEdit As IFeatureEdit\r\nIFeatureEdit featureEdit;\r\n\r\n\/\/    Dim pLine As ILine\r\nILine line;\r\n\r\n\/\/    Dim pMoveSet As ISet\r\nISet moveSet;\r\n\r\n\/\/    Dim pSpatialReference As ISpatialReference\r\nISpatialReference spatialReference;\r\n\r\n\/\/    Dim pStartPoint As IPoint\r\nIPoint startPoint = null;\r\n\r\n\/\/    Dim pEndPoint As IPoint\r\nIPoint endPoint = null;\r\n    \r\n\/\/    Dim origX As Double\r\ndouble originX;\r\n\r\n\/\/    Dim origY As Double\r\ndouble originY;\r\n\r\n\/\/    Dim bInOperation As Boolean\r\n\/\/ Not needed.\r\n    \r\n\/\/    Dim Dlg_Result As String\r\n\/\/ Not needed.\r\n\r\n\/\/    Dim Offset_SizeX As Integer\r\n\/\/ Change to double.\r\ndouble offsetSizeX;\r\n\r\n\/\/    Dim Offset_SizeY As Integer\r\n\/\/ Change to double.\r\ndouble offsetSizeY;\r\n\r\n\/\/    Dim DistanceX As Integer\r\n\/\/ Change to double.\r\ndouble distanceX;\r\n\r\n\/\/    Dim DistanceY As Integer\r\n\/\/ Change to double.\r\ndouble distanceY;\r\n\r\n\/\/    Dim StaggerIndex As Integer\r\nint staggerIndex;\r\n\r\n\/\/    Dim F_Count As Long\r\nint featureCount;\r\n  \r\n\/\/    On Error GoTo ErrorHandler\r\n\/\/ Use C# exception handling.\r\n...\r\n<\/pre>\n<p>The above declared ArcObjects required the following <code>using<\/code> statements and references to the assemblies added to the project.<\/p>\n<pre lang=\"csharp\" line=\"5\">\r\n...\r\nusing ESRI.ArcGIS.ArcMapUI;\r\nusing ESRI.ArcGIS.Carto;\r\nusing ESRI.ArcGIS.Geodatabase;\r\nusing ESRI.ArcGIS.esriSystem;\r\nusing ESRI.ArcGIS.Editor;\r\nusing ESRI.ArcGIS.Geometry;\r\n...\r\n<\/pre>\n<h2>Convert the operational code<\/h2>\n<p>Continue working in the <code>Perform()<\/code> method in the <em>StaggerOffsetButton.cs <\/em>file in the code editor.<\/p>\n<p>Following is the mostly line-by-line conversion of the VBA operational code to C#. Some sections are converted as blocks for clarity.<\/p>\n<pre lang=\"csharp\" line=\"132\">\r\n...\r\n\/\/    Set pMxDoc = ThisDocument\r\nmxDocument = ArcMap.Document;\r\n    \r\n\/\/    Set pLayer = pMxDoc.SelectedLayer\r\nlayer = mxDocument.SelectedLayer;\r\n    \r\n\/\/    ' Make sure some type of layer is selected\r\n\/\/    If (pLayer Is Nothing) Then\r\n\/\/        MsgBox \"Please Select a feature layer to offset\", vbOKOnly, sToolName\r\n\/\/        Exit Sub\r\n\/\/    End If\r\nif (layer == null)\r\n{\r\n    MessageBox.Show(\"Please Select a feature layer to offset\", toolName, MessageBoxButtons.OK);\r\n    return;\r\n}\r\n    \r\n\/\/    ' Make sure a feature layer (not a group layer) is selected\r\n\/\/    If Not (TypeOf pLayer Is IFeatureLayer) Then\r\n\/\/        MsgBox \"Please Select a feature layer\", vbOKOnly, sToolName\r\n\/\/        Exit Sub\r\n\/\/    End If\r\nif (!(layer is IFeatureLayer))\r\n{\r\n    MessageBox.Show(\"Please Select a feature layer to offset\", toolName, MessageBoxButtons.OK);\r\n    return;\r\n}\r\n    \r\n\/\/    Set pFeatureLayer = pMxDoc.SelectedLayer\r\n\/\/    Set pLayer = pFeatureLayer\r\nfeatureLayer = (IFeatureLayer)layer;\r\n    \r\n\/\/    ' Get count of features\r\n\/\/    F_Count = pFeatureLayer.FeatureClass.FeatureCount(Nothing)\r\nfeatureCount = featureLayer.FeatureClass.FeatureCount(null);\r\n    \r\n\/\/    ' Display a form to get offset values\r\n\/\/    form_OffsetFeatures.pPrompt.Caption = \"Move \" & F_Count & \" features in:\" & _\r\n\/\/            vbNewLine & pFeatureLayer.Name\r\n\/\/    form_OffsetFeatures.Show\r\n\/\/    If form_OffsetFeatures.Canceled Then\r\n\/\/        Exit Sub\r\n\/\/    Else\r\n\/\/        Offset_SizeX = form_OffsetFeatures.MoveDistX\r\n\/\/        Offset_SizeY = form_OffsetFeatures.MoveDistY\r\n\/\/    End If\r\n\r\n\/\/ Set the Layer Info\r\nstring layerInfo = \"Move \" + featureCount.ToString() + \" features in:\\n\" + featureLayer.Name;\r\n\r\n\/\/ Create the form\r\nfrmStaggerOffset staggerOffsetDialog = new frmStaggerOffset(layerInfo);\r\n\r\n\/\/ Display the form as a modal dialog\r\nstaggerOffsetDialog.ShowDialog();\r\n\r\n\/\/ Check if form was cancelled\r\nif (staggerOffsetDialog.DialogResult != DialogResult.OK)\r\n{\r\n    \/\/ abort\r\n    return;\r\n}\r\n\r\n\/\/ Get the offset values from the form\r\noffsetSizeX = staggerOffsetDialog.OffsetX;\r\noffsetSizeY = staggerOffsetDialog.OffsetY;\r\n\r\n                   \r\n    \r\n\/\/    ' Get a reference to the editor extension\r\n\/\/    pID = \"esriEditor.Editor\"\r\n\/\/    Set pEditor = Application.FindExtensionByCLSID(pID)\r\neditorUID.Value = \"esriEditor.Editor\";\r\neditor = ArcMap.Application.FindExtensionByCLSID(editorUID) as IEditor;\r\n\r\n    \r\n\/\/    ' Create an edit operation enabling undo for the operation\r\n\/\/    pEditor.StartOperation\r\n\/\/    bInOperation = True\r\neditor.StartOperation();\r\n\r\n\/\/ Use C# exception handling to abort edit operation if not completed\r\ntry\r\n{\r\n\r\n    \/\/    Set pCursor = pFeatureLayer.FeatureClass.Update(Nothing, False)\r\n    featureCursor = featureLayer.FeatureClass.Update(null, false);\r\n\r\n    \/\/    Set pFeature = pCursor.NextFeature\r\n\r\n    \/\/    ' Cause the staggered offset to be centered on original position\r\n    \/\/    StaggerIndex = F_Count \/ -2\r\n    staggerIndex = featureCount \/ -2;\r\n\r\n    \/\/    While (Not pFeature Is Nothing)\r\n    while ((feature = featureCursor.NextFeature()) != null)\r\n    {\r\n        \/\/        ' Select the feature\r\n        \/\/        pMxDoc.FocusMap.SelectFeature pLayer, pFeature\r\n        mxDocument.FocusMap.SelectFeature(layer, feature);\r\n\r\n        \/\/        Set pMoveSet = New esriSystem.Set\r\n        moveSet = new SetClass();\r\n\r\n        \/\/        pMoveSet.Add pFeature\r\n        moveSet.Add(feature);\r\n\r\n        \/\/        ' Reset the Set\r\n        \/\/        pMoveSet.Reset\r\n        moveSet.Reset();\r\n\r\n        \/\/        ' MoveSet requires a line to specify the new location\r\n        \/\/        ' Use the selection anchor as a starting point for the line\r\n        \/\/        Set pStartPoint = pEditor.SelectionAnchor.Point\r\n        \/\/        Set pLine = New Line\r\n        \/\/        pStartPoint.QueryCoords origX, origY\r\n        \/\/        Set pEndPoint = New Point\r\n        startPoint = editor.SelectionAnchor.Point;\r\n        line = new LineClass();\r\n        startPoint.QueryCoords(out originX, out originY);\r\n        endPoint = new PointClass();\r\n\r\n        \/\/        ' Calculate the total offset for the selection\r\n        \/\/        ' Uses linear unit of data frame PCS\r\n        \/\/        DistanceX = Offset_SizeX * StaggerIndex\r\n        \/\/        DistanceY = Offset_SizeY * StaggerIndex\r\n        distanceX = offsetSizeX * staggerIndex;\r\n        distanceY = offsetSizeY * staggerIndex;\r\n\r\n        \/\/        pEndPoint.PutCoords (origX + DistanceX), (origY + DistanceY)\r\n        \/\/        pLine.PutCoords pStartPoint, pEndPoint\r\n        endPoint.PutCoords((originX + distanceX), (originY + distanceY));\r\n        line.PutCoords(startPoint, endPoint);\r\n\r\n        \/\/        ' Get the spatial reference from the map and assign it to the new line\r\n        \/\/        Set pSpatialReference = pEditor.Map.SpatialReference\r\n        spatialReference = editor.Map.SpatialReference;\r\n\r\n        \/\/        ' Set the spatial reference of the new line\r\n        \/\/        Set pLine.SpatialReference = pSpatialReference\r\n        line.SpatialReference = spatialReference;\r\n\r\n        \/\/        ' Do the move while looping through the set\r\n        \/\/        Set pFeatureEdit = pMoveSet.Next\r\n        \/\/        Do While Not pFeatureEdit Is Nothing\r\n        \/\/          ' Move all the selected features\r\n        \/\/          pFeatureEdit.MoveSet pMoveSet, pLine\r\n        \/\/          Set pFeatureEdit = pMoveSet.Next\r\n        \/\/        Loop\r\n        while ((featureEdit = moveSet.Next() as IFeatureEdit) != null)\r\n        {\r\n            \/\/ Move all the selected features\r\n            featureEdit.MoveSet(moveSet, line);\r\n        }\r\n\r\n        \/\/        pMoveSet.RemoveAll\r\n        moveSet.RemoveAll();\r\n\r\n        \/\/        pMxDoc.FocusMap.ClearSelection\r\n        mxDocument.FocusMap.ClearSelection();\r\n\r\n        \/\/        Set pFeature = pCursor.NextFeature\r\n        \/\/        StaggerIndex = StaggerIndex + 1\r\n        staggerIndex += 1;\r\n\r\n        \/\/    Wend\r\n    }\r\n    \r\n    \/\/    ' Stop the Edit Operation\r\n    \/\/    pEditor.StopOperation \"Move Selection\"\r\n    editor.StopOperation(\"Move Selection\");\r\n    \/\/    bInOperation = False\r\n}\r\ncatch (Exception)\r\n{\r\n    editor.AbortOperation();\r\n    \/\/ Re-throw the exception so that the outer handler reports it,\r\n    \/\/ and this method is exited.\r\n    throw;\r\n}\r\n        \r\n\/\/    pMxDoc.ActiveView.Refresh\r\nmxDocument.ActiveView.Refresh();\r\n    \r\n\/\/    ' Additionally move the selection anchor\r\n\/\/    pEditor.SelectionAnchor.MoveTo pEndPoint, pEditor.Display\r\nif (endPoint != null)\r\n{\r\n    editor.SelectionAnchor.MoveTo(endPoint, editor.Display);\r\n}\r\n    \r\n\/\/    Exit Sub\r\n  \r\n\/\/ErrorHandler:\r\n\/\/  If bInOperation Then\r\n\/\/    pEditor.AbortOperation\r\n\/\/    MsgBox \"Error moving features.\"\r\n\/\/  End If\r\n\/\/End Sub\r\n...\r\n<\/pre>\n<h2>Test and debug the new code<\/h2>\n<p>Continue working with the <em>StaggerOffsetButton.cs <\/em>file in the code editor, locate the <code>OnClick()<\/code> method and edit its contents to the following code:<\/p>\n<pre lang=\"csharp\" line=\"26\">\r\nprotected override void OnClick()\r\n{\r\n    try\r\n    {\r\n        \/\/ Run the converted VBA ArcObjects code.\r\n        Perform(); \r\n    }\r\n    catch (Exception ex)\r\n    {\r\n        MessageBox.Show(ex.Message + \"\\n\\n\" + ex.StackTrace);\r\n    } \r\n}\r\n<\/pre>\n<p>Start debugging (press green arrow button or F5).<\/p>\n<p>You will likely receive an error message:<br \/>\nThe type <code>ESRI.ArcGIS.Display.IAnchorPoint<\/code> is defined in an assembly that is not referenced.<\/p>\n<p>Add the <code>ESRI.ArcGIS.Display<\/code> assembly to the project to correct the error.<\/p>\n<p>Start debugging again.<\/p>\n<p>Wait for ArcMap to load. Once it opens, open the provided <em>VBAtoCS_Tutorial_01_v10.mxd <\/em>map. Your toolbar and button should be where you previously placed on a tool panel. <\/p>\n<p>Select the <em>Hwy_94_Overlaps<\/em> layer and start an edit session.<\/p>\n<p>Click the Add-In&#8217;s button to display the  dialog form. If you have not selected a feature layer you should get a message box from the Add-In.<\/p>\n<p>Enter 350 for the East-West Route value and click the <em>OK<\/em> button.<\/p>\n<p>You can use ArcMap&#8217;s <em>Undo<\/em> button to return the features to their original position, then run the Add-In again and try different values.<\/p>\n<p>When you are done testing, end the edit session and close ArcMap to return to Visual Studio and stop debugging.<\/p>\n<p><strong>Tutorial Navigation<\/strong> | Previous: <a href=\"..\/part-5-adding-utility-dialog-form\/\">Part 5: Adding the Utility&#8217;s Dialog Form<\/a> | Next: <a href=\"..\/part-7-deploying-the-add-in\/\">Part 7: Deploying the Add-in<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Tutorial Navigation | Previous: Part 5: Adding the Utility&#8217;s Dialog Form | Next: Part 7: Deploying the Add-in Continuing with the Visual Studio project from Part 5, we will now perform a mostly line-by-line conversion of the ArcObjects code used by the VBA utility. Note: At this stage, no attempt will be made to conform [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"parent":8,"menu_order":6,"comment_status":"open","ping_status":"open","template":"","meta":{"footnotes":""},"class_list":["post-31","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/gis.qtools.com\/blog\/wp-json\/wp\/v2\/pages\/31","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/gis.qtools.com\/blog\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/gis.qtools.com\/blog\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/gis.qtools.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/gis.qtools.com\/blog\/wp-json\/wp\/v2\/comments?post=31"}],"version-history":[{"count":3,"href":"https:\/\/gis.qtools.com\/blog\/wp-json\/wp\/v2\/pages\/31\/revisions"}],"predecessor-version":[{"id":89,"href":"https:\/\/gis.qtools.com\/blog\/wp-json\/wp\/v2\/pages\/31\/revisions\/89"}],"up":[{"embeddable":true,"href":"https:\/\/gis.qtools.com\/blog\/wp-json\/wp\/v2\/pages\/8"}],"wp:attachment":[{"href":"https:\/\/gis.qtools.com\/blog\/wp-json\/wp\/v2\/media?parent=31"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}