ArcIMS Select Buffer tool
ArcIMS_SelectBufferTool_VBNet\Default.aspx.vb
' Copyright 2010 ESRI
' 
' All rights reserved under the copyright laws of the United States
' and applicable international laws, treaties, and conventions.
' 
' You may freely redistribute and use this sample code, with or
' without modification, provided you include the original copyright
' notice and use restrictions.
' 
' See the use restrictions.
' 




Imports Microsoft.VisualBasic
Imports System
Imports System.Data
Imports System.Configuration
Imports System.Web
Imports System.Web.Security
Imports System.Web.UI
Imports System.Web.UI.WebControls
Imports System.Web.UI.WebControls.WebParts
Imports System.Web.UI.HtmlControls
Imports System.Collections

Public Partial Class _Default
  Inherits System.Web.UI.Page
  Implements System.Web.UI.ICallbackEventHandler
  Private m_ADFCallbackFunctionString As String
  Private m_ADFCallbackResultCollection As ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResultCollection
  Private m_ResourceIndex As Integer = 0
  Private m_NameValueCollection As System.Collections.Specialized.NameValueCollection

  ' ICallbackEventHandler implementation
  Public Sub RaiseCallbackEvent(ByVal eventArgs As String) Implements System.Web.UI.ICallbackEventHandler.RaiseCallbackEvent
    m_ADFCallbackResultCollection = New ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResultCollection()

    m_NameValueCollection = ESRI.ArcGIS.ADF.Web.UI.WebControls. CallbackUtility.ParseStringIntoNameValueCollection(eventArgs)
    Dim eventArg As String = m_NameValueCollection("EventArg")

    If eventArg.Equals("selectButton") Then
      ' Only select features, no buffer
      SelectionToolSelectAndBuffer(False)
    ElseIf eventArg.Equals("bufferSelectButton") Then
      ' Buffer and select from target layer, if set
      SelectionToolSelectAndBuffer(True)
    ElseIf eventArg.Equals("clearAllButton") OrElse eventArg.Equals("activeLayerDropDownList") Then
      ' Clear all dynamic layers and refresh map resource
      ClearAllLayers(True)
    End If
  End Sub

  Public Function GetCallbackResult() As String Implements System.Web.UI.ICallbackEventHandler.GetCallbackResult
    Return m_ADFCallbackResultCollection.ToString()
  End Function

  Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs)
    ' Generate custom callback function string for html buttons and active layer drop down list
    ' Page will process callback.
    m_ADFCallbackFunctionString = Page.ClientScript.GetCallbackEventReference(Me, "message", "processCallbackResult", "context", "postBackError", True)
    ' Upon change of active layer, map will clear all dynamic layers.
    activeLayerDropDownList.Attributes.Add("onchange", "CustomCallback(this.id)")
  End Sub

  Protected Sub Page_PreRender(ByVal sender As Object, ByVal e As EventArgs)
    If (Not IsPostBack) Then
      ' On initial prerender, update dropdown lists with layer names and unit options
      Dim mapFunctionality As ESRI.ArcGIS.ADF.Web.DataSources.IMapFunctionality = CType(Map1.GetFunctionality(m_ResourceIndex), ESRI.ArcGIS.ADF.Web.DataSources.IMapFunctionality)
      Dim gisResource As ESRI.ArcGIS.ADF.Web.DataSources.IGISResource = mapFunctionality.Resource
      Dim supported As Boolean = gisResource.SupportsFunctionality(GetType(ESRI.ArcGIS.ADF.Web.DataSources.IQueryFunctionality))

      If supported Then
        Dim queryFunctionality As ESRI.ArcGIS.ADF.Web.DataSources.IQueryFunctionality = CType(gisResource.CreateFunctionality(GetType(ESRI.ArcGIS.ADF.Web.DataSources.IQueryFunctionality), Nothing), ESRI.ArcGIS.ADF.Web.DataSources.IQueryFunctionality)

        Dim layerIDs As String() = Nothing
        Dim layerNames As String() = Nothing
        queryFunctionality.GetQueryableLayers(Nothing, layerIDs, layerNames)

        selectLayerDropDownList.Items.Add("none")
        bufferSelectLayerDropDownList.Items.Add("none")
        Dim i As Integer = 0
        Do While i < layerNames.Length
          activeLayerDropDownList.Items.Add(layerNames(i))
          selectLayerDropDownList.Items.Add(layerNames(i))
          bufferSelectLayerDropDownList.Items.Add(layerNames(i))
          i += 1
        Loop
      End If

      Dim imsBufferUnits As Array = System.Enum.GetValues(GetType(ESRI.ArcGIS.ADF.IMS.Carto.Layer.BufferUnits))
      For Each imsBufferUnit As Integer In imsBufferUnits
        bufferToolUnitsDropDownList.Items.Add(imsBufferUnits.GetValue(imsBufferUnit).ToString())
        bufferActiveUnitsDropDownList.Items.Add(imsBufferUnits.GetValue(imsBufferUnit).ToString())
      Next imsBufferUnit
    End If

    ' On load of page content in the browser, execute some JavaScript to add custom element parameters to all 
    ' Web ADF postbacks.  Also, create a custom JavaScript function to initiate custom callback to the page and
    ' package element values.  
    Dim scriptKeyCustom As String = "customChangeScript"
    If (Not Me.Page.ClientScript.IsClientScriptBlockRegistered(Me.GetType(), scriptKeyCustom)) AndAlso (Not Page.IsPostBack) Then
      Dim scriptBlock As String = "" & ControlChars.CrLf & "                " & ControlChars.CrLf & "                function onLoadFunction() {" & ControlChars.CrLf & "                    var theform = document.forms[0];" & ControlChars.CrLf & "                    var original_value = theform.elements[""ESRIWebADFHiddenFields""].value;" & ControlChars.CrLf & "                    var new_value = original_value + "",{0},{1},{2},{3}"";" & ControlChars.CrLf & "                    theform.elements[""ESRIWebADFHiddenFields""].value = new_value;    " & ControlChars.CrLf & "                }" & ControlChars.CrLf & ControlChars.CrLf & "                function CustomCallback(argument){" & ControlChars.CrLf & "                    var message = ""EventArg="" + argument + ""&"";" & ControlChars.CrLf & "                    message += ""{0}="" + document.getElementById('{0}').value + ""&"";" & ControlChars.CrLf & "                    message += ""{4}="" + document.getElementById('{4}').value + ""&"";" & ControlChars.CrLf & "                    message += ""{5}="" + document.getElementById('{5}').value + ""&"";" & ControlChars.CrLf & "                    message += ""{6}="" + document.getElementById('{6}').value;" & ControlChars.CrLf & "                    var context = null;" & ControlChars.CrLf & "                  {7}" & ControlChars.CrLf & "                }" & ControlChars.CrLf & " " & ControlChars.CrLf & "                "

      scriptBlock = scriptBlock.Replace("{0}", activeLayerDropDownList.UniqueID)
      scriptBlock = scriptBlock.Replace("{1}", bufferToolDistanceTextBox.UniqueID)
      scriptBlock = scriptBlock.Replace("{2}", bufferToolUnitsDropDownList.UniqueID)
      scriptBlock = scriptBlock.Replace("{3}", bufferSelectLayerDropDownList.UniqueID)

      scriptBlock = scriptBlock.Replace("{4}", selectLayerDropDownList.UniqueID)
      scriptBlock = scriptBlock.Replace("{5}", bufferActiveDistanceTextBox.UniqueID)
      scriptBlock = scriptBlock.Replace("{6}", bufferActiveUnitsDropDownList.UniqueID)

      scriptBlock = scriptBlock.Replace("{7}", m_ADFCallbackFunctionString)

      Me.Page.ClientScript.RegisterClientScriptBlock(Me.GetType(), scriptKeyCustom, scriptBlock, True)
    End If

    Dim scriptKey As String = "loadScript"
    If (Not Me.Page.ClientScript.IsClientScriptBlockRegistered(Me.GetType(), scriptKey)) AndAlso (Not Page.IsPostBack) Then
      ' if Mozilla browser, use DOMContentLoaded event, else add to body onload
      Dim scriptBlock As String = "" & ControlChars.CrLf & "                if (document.addEventListener) {    " & ControlChars.CrLf & "                    document.addEventListener(""DOMContentLoaded"", onLoadFunction , false);" & ControlChars.CrLf & "                } else {" & ControlChars.CrLf & "                    top.document.body.onload = onLoadFunction;" & ControlChars.CrLf & "                }" & ControlChars.CrLf & "                                "
      Me.Page.ClientScript.RegisterClientScriptBlock(Me.GetType(), scriptKey, scriptBlock, True)
    End If
  End Sub

  Private Sub ClearAllLayers(ByVal initialCallback As Boolean)
    Dim imsMapFunctionality As ESRI.ArcGIS.ADF.Web.DataSources.IMS.MapFunctionality = CType(Map1.GetFunctionality(m_ResourceIndex), ESRI.ArcGIS.ADF.Web.DataSources.IMS.MapFunctionality)
    Dim mapView As ESRI.ArcGIS.ADF.IMS.Carto.MapView = imsMapFunctionality.MapView

        For Each layerName As String In New LayerNames()
            Dim layer As ESRI.ArcGIS.ADF.IMS.Carto.Layer.Layer = mapView.Layers.FindByName(layerName)
            If Not layer Is Nothing Then
                If layer.Name = LayerNames.SelectionToolActive Then
                    ' Remove active selection layer and filter from session if 
                    ' the clearAllButton button is pressed.  Otherwise, keep active 
                    ' selection layer.
                    If initialCallback Then
                        Session("activeLayerFilter") = Nothing
                        mapView.Layers.Remove(layer)
                    End If
                Else
                    mapView.Layers.Remove(layer)
                End If
            End If
        Next layerName

    ' Only refresh Map and return callback response if the clearAllButton button is pressed.
    If initialCallback Then

      If Map1.ImageBlendingMode = ESRI.ArcGIS.ADF.Web.UI.WebControls.ImageBlendingMode.Browser Then
        Map1.RefreshResource(imsMapFunctionality.Resource.Name)
      Else
        Map1.Refresh()
      End If
      m_ADFCallbackResultCollection.CopyFrom(Map1.CallbackResults)
    End If

  End Sub

  ' For ArcMap services, all dynamic feature layers must have a null renderer.  
  ' Renderers are defined in the mxd document.  Each feature layer can define its own selection renderer. 
  ' Buffers on feature layers use the default selection color for the data frame.  
  Private Sub SelectionToolSelectAndBuffer(ByVal bufferAndSelect As Boolean)
    ' Get argument values from client.  Popluated in RaiseCallbackEvent() method.
    Dim activeLayerName As String = m_NameValueCollection("activeLayerDropDownList")
    Dim targetLayerName As String = m_NameValueCollection("selectLayerDropDownList")
    Dim bufferDistanceString As String = m_NameValueCollection("bufferActiveDistanceTextBox")
    Dim bufferUnitsString As String = m_NameValueCollection("bufferActiveUnitsDropDownList")

    Dim imsMapFunctionality As ESRI.ArcGIS.ADF.Web.DataSources.IMS.MapFunctionality = CType(Map1.GetFunctionality(m_ResourceIndex), ESRI.ArcGIS.ADF.Web.DataSources.IMS.MapFunctionality)

    Dim mapview As ESRI.ArcGIS.ADF.IMS.Carto.MapView = imsMapFunctionality.MapView
    Dim imsLayerCollection As ESRI.ArcGIS.ADF.IMS.Carto.Layer.LayerCollection = mapview.Layers

    ' Clear dynamic layers (selections, buffers, IMS acetate layers) except active layer selection
    ClearAllLayers(False)

    Dim activeLayer As ESRI.ArcGIS.ADF.IMS.Carto.Layer.FeatureLayer = CType(imsLayerCollection.FindByName(activeLayerName), ESRI.ArcGIS.ADF.IMS.Carto.Layer.FeatureLayer)

    ' Get the filter applied by the selection tool on the active layer
    Dim activeLayerFilter As ESRI.ArcGIS.ADF.IMS.Carto.Layer.Filter = CType(Session("activeLayerFilter"), ESRI.ArcGIS.ADF.IMS.Carto.Layer.Filter)

    ' If target layer is set, get it
    Dim targetLayer As ESRI.ArcGIS.ADF.IMS.Carto.Layer.FeatureLayer = Nothing
    If targetLayerName <> "none" Then
      targetLayer = CType(imsLayerCollection.FindByName(targetLayerName), ESRI.ArcGIS.ADF.IMS.Carto.Layer.FeatureLayer)
    End If

    ' Default buffer distance of 0, unless explicitly set in a request.
    Dim bufferDistance As Single
    If (Not Single.TryParse(bufferDistanceString, bufferDistance)) Then
      bufferDistance = 0.0F
    End If

    ' Default buffer units of Decimal Degrees, unless explicitly set in a request.
    ' As an enumeration, this is only a placeholder.  The default of Decimal Degrees
    ' is only used when buffering polygons and the distance is 0.
    Dim imsBufferUnits As ESRI.ArcGIS.ADF.IMS.Carto.Layer.BufferUnits = ESRI.ArcGIS.ADF.IMS.Carto.Layer.BufferUnits.Decimal_Degrees

    If bufferAndSelect Then
      ' Get buffer units from user
      imsBufferUnits = CType(System.Enum.Parse(GetType(ESRI.ArcGIS.ADF.IMS.Carto.Layer.BufferUnits), bufferUnitsString, True), ESRI.ArcGIS.ADF.IMS.Carto.Layer.BufferUnits)

      ' Draw the buffer 
      Dim displayBuffer As ESRI.ArcGIS.ADF.IMS.Carto.Layer.DisplayBuffer = New ESRI.ArcGIS.ADF.IMS.Carto.Layer.DisplayBuffer()
      displayBuffer.Distance = bufferDistance
      displayBuffer.Units = imsBufferUnits

      ' Construct dynamic buffer feature layer.  ArcMap services require a null renderer.
      Dim bufferLayer As ESRI.ArcGIS.ADF.IMS.Carto.Layer.FeatureLayer = Nothing

      If imsMapFunctionality.MapResource.MapService.Type = ESRI.ArcGIS.ADF.IMS.ServiceType.ArcMapServer Then
        bufferLayer = activeLayer.CreateBufferLayer(activeLayerFilter, displayBuffer, Nothing, LayerNames.SelectionToolBuffer)
      Else
        ' Renderer for buffer, always a polygon
        Dim bufferSimpleRenderer As ESRI.ArcGIS.ADF.IMS.Display.Renderer.SimpleRenderer = New ESRI.ArcGIS.ADF.IMS.Display.Renderer.SimpleRenderer()
        Dim bufferSimpleFillSymbol As ESRI.ArcGIS.ADF.IMS.Display.Symbol.SimpleFillSymbol = New ESRI.ArcGIS.ADF.IMS.Display.Symbol.SimpleFillSymbol()
        bufferSimpleFillSymbol.Color = System.Drawing.Color.Green

        ' Transparency in percent instead of 0-1
        bufferSimpleFillSymbol.Transparency = 50.0
        bufferSimpleRenderer.Symbol = bufferSimpleFillSymbol

        bufferLayer = activeLayer.CreateBufferLayer(activeLayerFilter, displayBuffer, bufferSimpleRenderer, LayerNames.SelectionToolBuffer)
      End If
      bufferLayer.Name = LayerNames.SelectionToolBuffer

      ' *** Add dynamic buffer layer to the map
      mapview.Layers.Add(bufferLayer)
    End If

    ' If selecting feature in a target layer, the following code executes
    If Not targetLayer Is Nothing Then
      ' Create a layer to store the selected features in the target layer 
      Dim targetSelectionLayer As ESRI.ArcGIS.ADF.IMS.Carto.Layer.FeatureLayer = Nothing

      ' In ArcIMS, all feature layers of geometry type point, line, or polygon can be buffered using a value
      ' great than 0.  Only feature layers of type polygon can be buffered using a distance of 0 
      ' (essentially a layer on layer selection).   So if the buffer distance is greater than 0 or the feature 
      ' type is polygon, a buffer can be constructed to select features in a target layer.
      If bufferDistance > 0 OrElse activeLayer.Type = ESRI.ArcGIS.ADF.IMS.FeatureType.Polygon Then
        Dim activeLayerSelectionBuffer As ESRI.ArcGIS.ADF.IMS.Carto.Layer.SelectionBuffer = New ESRI.ArcGIS.ADF.IMS.Carto.Layer.SelectionBuffer(targetLayer, String.Empty)

        ' If bufferSelectButton is pressed
        If bufferAndSelect Then
          activeLayerSelectionBuffer.Distance = bufferDistance
          activeLayerSelectionBuffer.Units = imsBufferUnits
        Else ' Only used if the active layer is of type polygon
          activeLayerSelectionBuffer.Distance = 0
          activeLayerSelectionBuffer.Units = ESRI.ArcGIS.ADF.IMS.Carto.Layer.BufferUnits.Decimal_Degrees
        End If

        If imsMapFunctionality.MapResource.MapService.Type = ESRI.ArcGIS.ADF.IMS.ServiceType.ArcMapServer Then
          targetSelectionLayer = activeLayer.CreateBufferSelectionLayer(activeLayerFilter, activeLayerSelectionBuffer, Nothing, LayerNames.SelectionToolTarget)
        Else
          targetSelectionLayer = activeLayer.CreateBufferSelectionLayer(activeLayerFilter, activeLayerSelectionBuffer, SelectionToolTargetLayerRenderer(targetLayer.Type), LayerNames.SelectionToolTarget)
        End If
      Else ' If buffer distance is 0 and active layer is of type point or line

        ' Construct a query to return feature geometry selected in the active layer
        Dim activeLayerQueryParameters As ESRI.ArcGIS.ADF.IMS.Carto.Layer.QueryParameters = New ESRI.ArcGIS.ADF.IMS.Carto.Layer.QueryParameters(activeLayerFilter)
        activeLayerQueryParameters.ReturnGeometries = True
        Dim activeLayerQueryFeatureTable As ESRI.ArcGIS.ADF.IMS.Carto.Layer.FeatureTable = activeLayer.Query(activeLayerQueryParameters)

        ' Find the shape field               
        Dim shapeFieldIndex As Integer = -1
        Dim index As Integer = 0
        Do While index < activeLayerQueryFeatureTable.Columns.Count
          If activeLayerQueryFeatureTable.Columns(index).DataType Is GetType(ESRI.ArcGIS.ADF.IMS.Geometry.Geometry) Then
            shapeFieldIndex = index
            Exit Do
          End If
          index += 1
        Loop

        ' Package the selected feature geometry in a simple Multipoint or Polyline used to create
        ' a selection layer
        Dim imsGeometry As ESRI.ArcGIS.ADF.IMS.Geometry.Geometry = Nothing

        If activeLayer.Type = ESRI.ArcGIS.ADF.IMS.FeatureType.Point Then
          Dim imsSelectionMultipoint As ESRI.ArcGIS.ADF.IMS.Geometry.Multipoint = New ESRI.ArcGIS.ADF.IMS.Geometry.Multipoint()
          For Each dataRow As DataRow In activeLayerQueryFeatureTable.Rows
            Dim imsFeatureMultipoint As ESRI.ArcGIS.ADF.IMS.Geometry.Multipoint = CType(dataRow(shapeFieldIndex), ESRI.ArcGIS.ADF.IMS.Geometry.Multipoint)
            For Each imsPoint As ESRI.ArcGIS.ADF.IMS.Geometry.Point In imsFeatureMultipoint.Points
              imsSelectionMultipoint.Points.Add(imsPoint)
            Next imsPoint
          Next dataRow
          imsGeometry = imsSelectionMultipoint
        ElseIf activeLayer.Type = ESRI.ArcGIS.ADF.IMS.FeatureType.Line Then
          Dim imsSelectionPolyline As ESRI.ArcGIS.ADF.IMS.Geometry.Polyline = New ESRI.ArcGIS.ADF.IMS.Geometry.Polyline()
          For Each dataRow As DataRow In activeLayerQueryFeatureTable.Rows
            Dim imsFeaturePolyline As ESRI.ArcGIS.ADF.IMS.Geometry.Polyline = CType(dataRow(shapeFieldIndex), ESRI.ArcGIS.ADF.IMS.Geometry.Polyline)
            For Each imsPath As ESRI.ArcGIS.ADF.IMS.Geometry.Path In imsFeaturePolyline.Paths
              imsSelectionPolyline.Paths.Add(imsPath)
            Next imsPath
          Next dataRow
          imsGeometry = imsSelectionPolyline
        End If

        ' Create a filter to select features in the target layer
        activeLayerFilter = New ESRI.ArcGIS.ADF.IMS.Carto.Layer.Filter()
        activeLayerFilter.Geometry = imsGeometry

        If imsMapFunctionality.MapResource.MapService.Type = ESRI.ArcGIS.ADF.IMS.ServiceType.ArcMapServer Then
          targetSelectionLayer = targetLayer.CreateSelectionLayer(activeLayerFilter, Nothing, LayerNames.SelectionToolTarget)
        Else
          targetSelectionLayer = targetLayer.CreateSelectionLayer(activeLayerFilter, SelectionToolTargetLayerRenderer(targetLayer.Type), LayerNames.SelectionToolTarget)
        End If
      End If

      targetSelectionLayer.Name = LayerNames.SelectionToolTarget
      ' *** Add dynamic selection from the target layer to the map
      mapview.Layers.Add(targetSelectionLayer)
    End If

    If Map1.ImageBlendingMode = ESRI.ArcGIS.ADF.Web.UI.WebControls.ImageBlendingMode.Browser Then
      Map1.RefreshResource(imsMapFunctionality.Resource.Name)
    Else
      Map1.Refresh()
    End If

    m_ADFCallbackResultCollection.CopyFrom(Map1.CallbackResults)
  End Sub

  ' Create a renderer for the selected features in the target layer defined in the SelectionTool
  Private Function SelectionToolTargetLayerRenderer(ByVal targetFeatureType As ESRI.ArcGIS.ADF.IMS.FeatureType) As ESRI.ArcGIS.ADF.IMS.Display.Renderer.SimpleRenderer
    Dim targetSelectionSimpleRenderer As ESRI.ArcGIS.ADF.IMS.Display.Renderer.SimpleRenderer = New ESRI.ArcGIS.ADF.IMS.Display.Renderer.SimpleRenderer()

    Dim targetSelectionFeatureSymbol As ESRI.ArcGIS.ADF.IMS.Display.Symbol.FeatureSymbol = Nothing

        If targetFeatureType = ESRI.ArcGIS.ADF.IMS.FeatureType.Point Then
            Dim targetSelectionSimpleMarkerSymbol As ESRI.ArcGIS.ADF.IMS.Display.Symbol.SimpleMarkerSymbol = New ESRI.ArcGIS.ADF.IMS.Display.Symbol.SimpleMarkerSymbol()
            targetSelectionSimpleMarkerSymbol.Color = System.Drawing.Color.Red
            targetSelectionSimpleMarkerSymbol.Width = 8
            targetSelectionFeatureSymbol = targetSelectionSimpleMarkerSymbol
        ElseIf targetFeatureType = ESRI.ArcGIS.ADF.IMS.FeatureType.Line Then
            Dim targetSelectionSimpleLineSymbol As ESRI.ArcGIS.ADF.IMS.Display.Symbol.SimpleLineSymbol = New ESRI.ArcGIS.ADF.IMS.Display.Symbol.SimpleLineSymbol()
            targetSelectionSimpleLineSymbol.Width = 2
            targetSelectionSimpleLineSymbol.Color = System.Drawing.Color.Red
            targetSelectionFeatureSymbol = targetSelectionSimpleLineSymbol
        ElseIf targetFeatureType = ESRI.ArcGIS.ADF.IMS.FeatureType.Polygon Then
            Dim targetSelectionSimpleFillSymbol As ESRI.ArcGIS.ADF.IMS.Display.Symbol.SimpleFillSymbol = New ESRI.ArcGIS.ADF.IMS.Display.Symbol.SimpleFillSymbol()
            targetSelectionSimpleFillSymbol.Color = System.Drawing.Color.Red
            targetSelectionFeatureSymbol = targetSelectionSimpleFillSymbol
        End If

    If Not targetSelectionFeatureSymbol Is Nothing Then
      targetSelectionFeatureSymbol.Transparency = 50.0
    End If

    targetSelectionSimpleRenderer.Symbol = targetSelectionFeatureSymbol

    Return targetSelectionSimpleRenderer
  End Function
End Class