C# - Create new layer / shape programmaticaly

3897
8
10-18-2011 02:48 PM
GalinaLapushinskaya
New Contributor
Hi,
I'm C# programmer and have some knowledge about working with ArcGIS Desktop 10. But I'm new at ArcObjects in C#. Can somebody give me an example, how I can add a new layer to existing MXD map in C# from XY table? Examples which I found before didn't work. Can I do this from dataset or we need to generate some extra files like TXT or XLS?

Thank you
0 Kudos
8 Replies
JamesCrandall
MVP Frequent Contributor
Hi,
I'm C# programmer and have some knowledge about working with ArcGIS Desktop 10. But I'm new at ArcObjects in C#. Can somebody give me an example, how I can add a new layer to existing MXD map in C# from XY table? Examples which I found before didn't work. Can I do this from dataset or we need to generate some extra files like TXT or XLS?

Thank you


When you say "dataset", do you mean x/y values in an ADO.NET DataSet/DataTable?
0 Kudos
GalinaLapushinskaya
New Contributor
When you say "dataset", do you mean x/y values in an ADO.NET DataSet/DataTable?


Yes, if possible. We can use ADO.NET datatable or DBF / EXCEL file. The main question is how to create the layer from the existing data.

Thank you!
0 Kudos
JamesCrandall
MVP Frequent Contributor
Galina,

You have a couple of options -- create an X/Y event layer or generate a brand new point layer.  Here's a Sub I developed that accepts an ADO.NET DataTable of Latitude and Longitude values, connects to an existing Personal Geodatabase, creates a new point FeatureClass in that PGDB and adds it to the TOC.  This accepts the DataTable and a name string variable to build the layer, so you may have to alter the path/location of the PGDB and the lat/lon field names to your specifications.

Also, adjust the CoordSystem parameters.

Public Sub buildNewLayer(ByVal inDT As DataTable, _
                                   ByVal LayerName As String)
        Dim pFeatureClass As IFeatureClass

        Dim pSpRFc As SpatialReferenceEnvironment
        pSpRFc = New SpatialReferenceEnvironment

        'Setup Geographic CoordSys for GPS input pts
        Dim pGCS As IGeographicCoordinateSystem
        Dim pSpRefWGS As ISpatialReference
        pGCS = pSpRFc.CreateGeographicCoordinateSystem(esriSRGeoCSType.esriSRGeoCS_WGS1984)
        pGCS.SetDomain(-200, 200, -200, 200)
        pSpRefWGS = pGCS

        'Setup Projected CoordSys for GPS output pts
        Dim pPCS As IProjectedCoordinateSystem
        Dim pSpRefNAD83 As ISpatialReference
        pPCS = pSpRFc.CreateProjectedCoordinateSystem(esriSRProjCSType.esriSRProjCS_NAD1983SPCS_FLWestFT)
        pPCS.SetDomain(420000, 690000, 880000, 1150000)
        pSpRefNAD83 = pPCS

        'GeoTransformation declared
        Dim pGeoTrans As IGeoTransformation
        pGeoTrans = MakeGeoTrans(pSpRefWGS, pSpRefNAD83)

        '**Open the PGDB for temp layers
        Dim db_path As String = "C:\MyPGDB.mdb"  'name your PGDB here

        Dim pWS As IWorkspace
        Dim pFWS As IFeatureWorkspace
        Dim pWorkspaceFactory As IWorkspaceFactory
        pWorkspaceFactory = New ESRI.ArcGIS.DataSourcesGDB.AccessWorkspaceFactory
        pFWS = pWorkspaceFactory.OpenFromFile(db_path, 0)
        pWS = pFWS

        ' Set up a simple fields collection
        Dim pFields As ESRI.ArcGIS.Geodatabase.IFields
        Dim pFieldsEdit As ESRI.ArcGIS.Geodatabase.IFieldsEdit
        pFields = New ESRI.ArcGIS.Geodatabase.Fields
        pFieldsEdit = New ESRI.ArcGIS.Geodatabase.Fields
        pFieldsEdit = pFields

        Dim pField As ESRI.ArcGIS.Geodatabase.IField
        Dim pFieldEdit As ESRI.ArcGIS.Geodatabase.IFieldEdit
        pField = New ESRI.ArcGIS.Geodatabase.Field
        pFieldEdit = pField

        '*** set up geometry field ***
        Dim pGeomDef As ESRI.ArcGIS.Geodatabase.IGeometryDef
        Dim pGeomDefedit As ESRI.ArcGIS.Geodatabase.IGeometryDefEdit
        pGeomDef = New ESRI.ArcGIS.Geodatabase.GeometryDef
        pGeomDefedit = pGeomDef
        With pGeomDefedit
            .GeometryType_2 = ESRI.ArcGIS.Geometry.esriGeometryType.esriGeometryPoint
            .SpatialReference_2 = pSpRefNAD83
        End With

        pField = New ESRI.ArcGIS.Geodatabase.Field
        pFieldEdit = pField
        pFieldEdit.Name_2 = "Shape"
        pFieldEdit.AliasName_2 = "Geometry"
        pFieldEdit.Type_2 = esriFieldType.esriFieldTypeGeometry
        pFieldEdit.GeometryDef_2 = pGeomDef
        pFieldsEdit.AddField(pField)

        '' create the object id field
        pField = New ESRI.ArcGIS.Geodatabase.Field
        pFieldEdit = pField
        pFieldEdit.Name_2 = "OBJECTID"
        pFieldEdit.Type_2 = esriFieldType.esriFieldTypeOID
        pFieldsEdit.AddField(pField)

        For i = 0 To inDT.Columns.Count - 1
            pField = New ESRI.ArcGIS.Geodatabase.Field
            pFieldEdit = pField
            With pFieldEdit 'set all the properties according to the columns in the recordset
                .Length_2 = inDT.Columns(i).MaxLength
                .Name_2 = inDT.Columns(i).ColumnName
                .Type_2 = ESRI.ArcGIS.Geodatabase.esriFieldType.esriFieldTypeInteger
            End With

            Dim ColName As String = inDT.Columns(i).ColumnName.ToString
            Dim dtColType As String = inDT.Columns(i).DataType.ToString

            If inDT.Columns(i).DataType.FullName.ToString = "System.Int32" Then
                pFieldEdit.Type_2 = ESRI.ArcGIS.Geodatabase.esriFieldType.esriFieldTypeInteger
            ElseIf inDT.Columns(i).DataType.FullName.ToString = "System.String" Then
                pFieldEdit.Type_2 = ESRI.ArcGIS.Geodatabase.esriFieldType.esriFieldTypeString
            ElseIf inDT.Columns(i).DataType.FullName.ToString = "System.Double" Then
                pFieldEdit.Type_2 = ESRI.ArcGIS.Geodatabase.esriFieldType.esriFieldTypeDouble
            ElseIf inDT.Columns(i).DataType.FullName.ToString = "System.Decimal" Then
                pFieldEdit.Type_2 = ESRI.ArcGIS.Geodatabase.esriFieldType.esriFieldTypeDouble
            ElseIf inDT.Columns(i).DataType.FullName.ToString = "System.DateTime" Then
                pFieldEdit.Type_2 = ESRI.ArcGIS.Geodatabase.esriFieldType.esriFieldTypeDate
            End If

            pFieldsEdit.AddField(pField)
        Next i

        Try

            '**Check for existing FeatClass and delete if present
            Dim pExistingDs As ESRI.ArcGIS.Geodatabase.IDataset
            Dim pEnumDataset As IEnumDataset
            pEnumDataset = pWS.Datasets(esriDatasetType.esriDTFeatureClass)

            pExistingDs = pEnumDataset.Next
            Do Until pExistingDs Is Nothing
                If pExistingDs.Name = LayerName Then
                    If pExistingDs.CanDelete Then
                        pExistingDs.Delete()
                    End If
                End If
                pExistingDs = pEnumDataset.Next
            Loop

            '** create a UID for simple features
            Dim pUID As ESRI.ArcGIS.esriSystem.UID
            pUID = New ESRI.ArcGIS.esriSystem.UID
            pUID.Value = UID_FEATURE

            ''** Create new FeatClass in PGDB
            pFeatureClass = pFWS.CreateFeatureClass(LayerName, _
                                                    pFields, _
                                                    pUID, _
                                                    Nothing, _
                                                    esriFeatureType.esriFTSimple, _
                                                    "Shape", "")

        Catch ex As Exception
            MsgBox(ex.ToString)
        End Try


        Dim pFeatCur As IFeatureCursor
        Dim pFeatBuf As IFeatureBuffer
        pFeatBuf = pFeatureClass.CreateFeatureBuffer
        pFeatCur = pFeatureClass.Insert(True)

        'Add attributes to the FeatClass from ADO.NET Datasource
        Dim tmpPoint As IPoint
        Dim pGeo As ESRI.ArcGIS.Geometry.IGeometry
        Dim dtCol As DataColumn
        Dim dtColname As String
        Dim row As DataRow

        Try

            For i = 0 To inDT.Rows.Count - 1
                row = inDT.Rows(i)

                If Not IsDBNull(row.Item("latitude")) And Not IsDBNull(row.Item("longitude")) Then

                    '***add the rest of the attributes
                    For Each dtCol In inDT.Columns
                        dtColname = dtCol.ColumnName.ToString
                        Dim dtColType As String = dtCol.DataType.ToString

                        If Not IsDBNull(row.Item(dtColname)) Then
                            pFeatBuf.Value(pFeatBuf.Fields.FindField(dtColname)) = row.Item(dtColname)
                        Else
                            If dtCol.DataType.FullName.ToString = "System.Int32" Then
                                pFeatBuf.Value(pFeatBuf.Fields.FindField(dtColname)) = CInt(0)
                            ElseIf dtCol.DataType.FullName.ToString = "System.String" Then
                                pFeatBuf.Value(pFeatBuf.Fields.FindField(dtColname)) = CStr("NA")
                            ElseIf dtCol.DataType.FullName.ToString = "System.Double" Then
                                pFeatBuf.Value(pFeatBuf.Fields.FindField(dtColname)) = CDbl(0.0)
                            ElseIf dtCol.DataType.FullName.ToString = "System.Decimal" Then
                                pFeatBuf.Value(pFeatBuf.Fields.FindField(dtColname)) = CDec(0.0)
                            ElseIf dtCol.DataType.FullName.ToString = "System.DateTime" Then
                                pFeatBuf.Value(pFeatBuf.Fields.FindField(dtColname)) = CDate(Now())
                            End If
                        End If
                    Next

                    '*Add the new point
                    tmpPoint = New ESRI.ArcGIS.Geometry.Point
                    tmpPoint.PutCoords((CDec(row.Item("longitude"))), CDec(row.Item("latitude")))

                    '*Set the new point to match Projected CoordSys of SDE FeatureClass'
                    pGeo = tmpPoint
                    pGeo.SpatialReference = pSpRefWGS
                    pGeo.Project(pSpRefNAD83)

                    '*Create a point
                    pGeo.SnapToSpatialReference()
                    pFeatBuf.Shape = pGeo
                    pFeatCur.InsertFeature(pFeatBuf)

                Else
                End If
            Next
            pFeatCur.Flush()
           
            Dim pDoc As ESRI.ArcGIS.ArcMapUI.IMxDocument
            Dim pMap As ESRI.ArcGIS.Carto.IMap
            pDoc = m_pApp.Document
            pMap = pDoc.FocusMap

            Dim pLayer As IFeatureLayer
            pLayer = New FeatureLayer
            pLayer.FeatureClass = pFeatureClass
            pLayer.Name = pFeatureClass.AliasName

            pDoc.AddLayer(pLayer)

        Catch ex As Exception
            MsgBox(ex.ToString)
            Me.Dispose()
        Finally
            DisposeCOMObject(pFeatCur)
        End Try

        pFeatBuf = Nothing
        pFeatureClass = Nothing

    End Sub
0 Kudos
JamesCrandall
MVP Frequent Contributor
An additional function you will need to add to complete the code previously posted:

    Function MakeGeoTrans(ByVal pFromSR As ISpatialReference, ByVal pToSR As ISpatialReference) As IGeoTransformation
        Dim pSRF As ISpatialReferenceFactory2
        pSRF = New SpatialReferenceEnvironment
        Dim pGeoTrans As IGeoTransformation

        'Set the transformation method you want (must be compatible with the input and output data sets)
        pGeoTrans = pSRF.CreateGeoTransformation(esriSRGeoTransformationType.esriSRGeoTransformation_NAD1983_To_WGS1984_1)
        pGeoTrans.PutSpatialReferences(pFromSR, pToSR)
        MakeGeoTrans = pGeoTrans
    End Function



Also, here is something else that might be useful if you are integrating ADO.NET into your GIS applications.  This is an example I've uploaded to ArcScritps that will take an IFeatureLayer and covert it to an ADO.NET DataTable, great for adding/filling DataGridViews in your GIS applications.

http://resources.arcgis.com/gallery/file/arcobjects-net-api/details?entryID=675318D8-1422-2418-8814-...
0 Kudos
GalinaLapushinskaya
New Contributor
Thank you for your help, James. I will try to do the layer today.
0 Kudos
GalinaLapushinskaya
New Contributor
Unfortunately code didn't work. I modified it a little but still get exception on the CreateFeatureBuffer.
I would like to give some explanation about what I'm trying to do. At the beginning I do not have any .mdb files. Only axMapControl on the form and MXD map file. Before opening this form, I'm trying to add a new layer to the existing map with some Points from the ADO.NET dataset.

Using your code I'm trying to create an empty mdb file and then set up its parameters. For UID.Value I'm using GUID Id for AddData.

Thank you
0 Kudos
JamesCrandall
MVP Frequent Contributor
Unfortunately code didn't work. I modified it a little but still get exception on the CreateFeatureBuffer.
I would like to give some explanation about what I'm trying to do. At the beginning I do not have any .mdb files. Only axMapControl on the form and MXD map file. Before opening this form, I'm trying to add a new layer to the existing map with some Points from the ADO.NET dataset.

Using your code I'm trying to create an empty mdb file and then set up its parameters. For UID.Value I'm using GUID Id for AddData.

Thank you


Code works perfectly fine for me.  So, yes it works.  This is coming out of an implementation I built that takes an ADO.NET DataTable (that has lat/lon values in it) and converts this into a Point FeatureLayer.

I never said this code would "create an empty mdb file".  Actually, I specifically show you where you need to change the path to the EXISTING Personal Geodatabase that you have already setup. 

You are getting your error on the CreateFeatureBuffer probably because pFeatureClass is getting set to Nothing.  Did you step thru the code?  What is pFeatureClass after it passes this line:

''** Create new FeatClass in PGDB
            pFeatureClass = pFWS.CreateFeatureClass(LayerName, _
                                                    pFields, _
                                                    pUID, _
                                                    Nothing, _
                                                    esriFeatureType.esriFTSimple, _
                                                    "Shape", "")


My guess is that it's nothing after this because, from what it sounds like in your post, that you don't have the PGDB already setup and connceting to it.  Check this line and make sure that the IFeatureWorkspace is getting set properly:

pFWS = pWorkspaceFactory.OpenFromFile(db_path, 0)
0 Kudos
GalinaLapushinskaya
New Contributor
Thank you for your reply. I will try to create personnel geodatabase file and try the code again.
0 Kudos