Common Add custom tool
Common_AddCustomTool_VBNet\App_Code\CustomToolLibrary.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
Namespace CustomToolLibrary
  Public Class ZoomToPointTool
        Implements ESRI.ArcGIS.ADF.Web.UI.WebControls.Tools.IMapServerToolAction
    #Region "IMapServerToolAction Members"

    Private Sub ServerAction(ByVal toolEventArgs As ESRI.ArcGIS.ADF.Web.UI.WebControls.ToolEventArgs) Implements ESRI.ArcGIS.ADF.Web.UI.WebControls.Tools.IMapServerToolAction.ServerAction
      ' Get reference to map control
      Dim adfMap As ESRI.ArcGIS.ADF.Web.UI.WebControls.Map = CType(toolEventArgs.Control, ESRI.ArcGIS.ADF.Web.UI.WebControls.Map)

      Try
        ' Cast tool event arguments to map point event arguments, which allows
        ' easy access to the map point clicked by the user
        Dim mapPointEventArgs As ESRI.ArcGIS.ADF.Web.UI.WebControls.MapPointEventArgs = CType(toolEventArgs, ESRI.ArcGIS.ADF.Web.UI.WebControls.MapPointEventArgs)
        ' Get the map point from the map point event arguments
        Dim adfPoint As ESRI.ArcGIS.ADF.Web.Geometry.Point = mapPointEventArgs.MapPoint

        ' Change map extent.  The resources have not changed in the Map control, thus 
        ' a call to Map.Refresh is not required. Note that the Map will generate the 
        ' callback response automatically.  You do not need to add the Map's callback 
        ' results to any other control or convert them to a string.
        Dim quarterMapExtentWidth As Double = adfMap.Extent.Width / 4

        Dim adfEnvelope As ESRI.ArcGIS.ADF.Web.Geometry.Envelope = New ESRI.ArcGIS.ADF.Web.Geometry.Envelope(adfPoint.X - quarterMapExtentWidth, adfPoint.Y - quarterMapExtentWidth, adfPoint.X + quarterMapExtentWidth, adfPoint.Y + quarterMapExtentWidth)
        adfMap.Extent = adfEnvelope
      Catch exception As System.Exception
        ' If an error occurred, get the callback result from the ProcessError
        ' function and copy to the map control's callback results collection
        adfMap.CallbackResults.Add(Utility.GetErrorCallback(exception))
      End Try
    End Sub

    #End Region
  End Class

  Public Class IdentifyAllTool
        Implements ESRI.ArcGIS.ADF.Web.UI.WebControls.Tools.IMapServerToolAction
    #Region "IMapServerToolAction Members"

    Private Sub ServerAction(ByVal toolEventArgs As ESRI.ArcGIS.ADF.Web.UI.WebControls.ToolEventArgs) Implements ESRI.ArcGIS.ADF.Web.UI.WebControls.Tools.IMapServerToolAction.ServerAction
      ' Get reference to the map control
      Dim adfMap As ESRI.ArcGIS.ADF.Web.UI.WebControls.Map = CType(toolEventArgs.Control, ESRI.ArcGIS.ADF.Web.UI.WebControls.Map)

      Try
        ' Cast tool event arguments to map point event arguments, which allows
        ' easy access to the map point clicked by the user
        Dim mapPointEventArgs As ESRI.ArcGIS.ADF.Web.UI.WebControls.MapPointEventArgs = CType(toolEventArgs, ESRI.ArcGIS.ADF.Web.UI.WebControls.MapPointEventArgs)
        ' Get the map point from the map point event arguments
        Dim adfPoint As ESRI.ArcGIS.ADF.Web.Geometry.Point = mapPointEventArgs.MapPoint

        ' Create a master dataset to store all tables returned from Identity operation
        Dim outputDataset As System.Data.DataSet = New System.Data.DataSet()

        ' For each map functionality (resource) in the Map, do an Identify
        For Each mapFunctionality As ESRI.ArcGIS.ADF.Web.DataSources.IMapFunctionality In adfMap.GetFunctionalities()
          ' Retrieve the resource for the current map functionality object
          Dim gisResource As ESRI.ArcGIS.ADF.Web.DataSources.IGISResource = mapFunctionality.Resource

          ' Check whether the current resource supports querying
          Dim supportsQuery As Boolean = gisResource.SupportsFunctionality(GetType(ESRI.ArcGIS.ADF.Web.DataSources.IQueryFunctionality))

          If supportsQuery Then
            ' Create a query functionality object from the current resource
            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)

            ' Get the names and ids of the queryable layers in the current resource
            Dim layerIDs As String()
            Dim layerNames As String()
            queryFunctionality.GetQueryableLayers(Nothing, layerIDs, layerNames)

            ' Initialize a variable to store tolerance.  This will be used as the tolerance
            ' around the point clicked by the user
            Dim pixelTolerance As Integer = 3

            ' Execute the identify operation
            Dim resultDataTableArray As System.Data.DataTable() = queryFunctionality.Identify(mapFunctionality.Name, adfPoint, pixelTolerance, ESRI.ArcGIS.ADF.Web.IdentifyOption.VisibleLayers, layerIDs)

            ' Exit the loop if no results were found
            If resultDataTableArray Is Nothing Then
              Exit For
            End If

            ' Add each table returned to the master dataset.  Give each table a unique name
            ' composed of the resource name, layer id, and layer name.
            Dim index As Integer = 0
            Do While index < resultDataTableArray.Length
              Dim resultDataTable As System.Data.DataTable = resultDataTableArray(index)
              ' Find the index of the layer name in the layerNames array
              ' corresponding to the current results table
              Dim i As Integer
              i = 0
              Do While i < layerNames.Length
                If resultDataTable.TableName = layerNames(i) Then
                  Exit Do
                End If
                i += 1
              Loop
              resultDataTable.TableName = gisResource.Name & "_" & layerIDs(i) & "_" & layerNames(i)
              outputDataset.Tables.Add(resultDataTable)
              index += 1
            Loop
          End If
        Next mapFunctionality


        ' For each table in the master dataset, create a GridView to display the content.  Write the rendered
        ' HTML content to a string for dynamic display in the browser
        Dim outputDataTableCollection As System.Data.DataTableCollection = outputDataset.Tables
        Dim tableHTMLString As String = String.Empty
        For Each dataTable As System.Data.DataTable In outputDataTableCollection
          If dataTable.Rows.Count = 0 Then
            Continue For
          End If
          Dim gridView As System.Web.UI.WebControls.GridView = New System.Web.UI.WebControls.GridView()
          gridView.ToolTip = dataTable.TableName
          gridView.Caption = dataTable.TableName
          gridView.DataSource = dataTable
          gridView.DataBind()
          gridView.Visible = True
          gridView.BorderWidth = 10

          Using stringWriter As System.IO.StringWriter = New System.IO.StringWriter()
            Dim htmlTextWriter As System.Web.UI.HtmlTextWriter = New System.Web.UI.HtmlTextWriter(stringWriter)
            gridView.RenderControl(htmlTextWriter)
            htmlTextWriter.Flush()
            tableHTMLString = tableHTMLString & stringWriter.ToString()
          End Using
        Next dataTable

        ' Use ADF callback mechanism to insert content into a div element in the page
        Dim tablesCallbackResult As ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResult = ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResult.CreateSetInnerContent("datadiv", tableHTMLString)

        adfMap.CallbackResults.Add(tablesCallbackResult)
      Catch exception As System.Exception
        ' If an error occurred, get the callback result from the ProcessError
        ' function and copy to the map control's callback results collection
        adfMap.CallbackResults.Add(Utility.GetErrorCallback(exception))
      End Try

    End Sub
    #End Region
  End Class

  Public Class ExtentCommand
        Implements ESRI.ArcGIS.ADF.Web.UI.WebControls.Tools.IMapServerCommandAction
    #Region "IMapServerCommandAction Members"

    Private Sub ServerAction(ByVal toolbarItemInfo As ESRI.ArcGIS.ADF.Web.UI.WebControls.Tools.ToolbarItemInfo) Implements ESRI.ArcGIS.ADF.Web.UI.WebControls.Tools.IServerAction.ServerAction
      ' Change map extent.  Since layer or resource content is 
      ' not changed, no call to Map.Refresh is needed.
      Dim adfMap As ESRI.ArcGIS.ADF.Web.UI.WebControls.Map = CType(toolbarItemInfo.BuddyControls(0), ESRI.ArcGIS.ADF.Web.UI.WebControls.Map)

      Try
        adfMap.Extent = New ESRI.ArcGIS.ADF.Web.Geometry.Envelope(-120, 30, -100, 40)
      Catch exception As System.Exception
        ' If an error occurred, get the callback result from the ProcessError
        ' function and copy to the map control's callback results collection
        adfMap.CallbackResults.Add(Utility.GetErrorCallback(exception))
      End Try
    End Sub

    #End Region
  End Class

  Public Class ExtentListDropDownBox
        Implements ESRI.ArcGIS.ADF.Web.UI.WebControls.Tools.IMapServerDropDownBoxAction
    #Region "IMapServerDropDownBoxAction Members"

    Private Sub ServerAction(ByVal toolbarItemInfo As ESRI.ArcGIS.ADF.Web.UI.WebControls.Tools.ToolbarItemInfo) Implements ESRI.ArcGIS.ADF.Web.UI.WebControls.Tools.IServerAction.ServerAction
      ' Get the value selected in Web ADF drop down box.  Change map extent and set Map.Extent to the new extent.
      ' Get the Web ADF map control
      Dim adfMap As ESRI.ArcGIS.ADF.Web.UI.WebControls.Map = CType(toolbarItemInfo.BuddyControls(0), ESRI.ArcGIS.ADF.Web.UI.WebControls.Map)

      Try
        ' Get the direction drop-down box and the currently selected value
        Dim directionDropDownBox As ESRI.ArcGIS.ADF.Web.UI.WebControls.DropDownBox = CType(toolbarItemInfo.Toolbar.ToolbarItems.Find(toolbarItemInfo.Name), ESRI.ArcGIS.ADF.Web.UI.WebControls.DropDownBox)
        Dim directionQuadrant As String = directionDropDownBox.SelectedValue

        ' Get the current map extent parameters
        Dim minx, miny, maxx, maxy As Double
        minx = adfMap.Extent.XMin
        miny = adfMap.Extent.YMin
        maxx = adfMap.Extent.XMax
        maxy = adfMap.Extent.YMax

        ' Calculate the width and height of the current map extent
        Dim xWidth As Double = maxx - minx
        Dim yHeight As Double = maxy - miny

        ' Calculate new extent parameters based on the currently selected
        ' value in the direction drop-down box
        Select Case directionQuadrant
          Case "NorthWest"
            miny = maxy
            maxy = maxy + yHeight
            maxx = minx
            minx = minx - xWidth
          Case "NorthEast"
            minx = maxx
            maxx = maxx + xWidth
            miny = maxy
            maxy = maxy + yHeight
          Case "SouthWest"
            maxx = minx
            minx = minx - xWidth
            maxy = miny
            miny = miny - yHeight
          Case "SouthEast"
            minx = maxx
            maxx = maxx + xWidth
            maxy = miny
            miny = miny - yHeight
        End Select

        ' Set the map control's extent to the new extent parameters
        adfMap.Extent = New ESRI.ArcGIS.ADF.Web.Geometry.Envelope(minx, miny, maxx, maxy)
      Catch exception As System.Exception
        ' If an error occurred, get the callback result from the ProcessError
        ' function and copy to the map control's callback results collection
        adfMap.CallbackResults.Add(Utility.GetErrorCallback(exception))
      End Try
    End Sub

    #End Region
  End Class

  Public Class HyperLinkTool
        Implements ESRI.ArcGIS.ADF.Web.UI.WebControls.Tools.IMapServerToolAction
    #Region "IMapServerToolAction Members"

    Private Sub ServerAction(ByVal toolEventArgs As ESRI.ArcGIS.ADF.Web.UI.WebControls.ToolEventArgs) Implements ESRI.ArcGIS.ADF.Web.UI.WebControls.Tools.IMapServerToolAction.ServerAction
      ' Get map control from passed-in arguments
      Dim adfMap As ESRI.ArcGIS.ADF.Web.UI.WebControls.Map = CType(toolEventArgs.Control, ESRI.ArcGIS.ADF.Web.UI.WebControls.Map)

      ' Cast tool event arguments to map point event arguments, which allows
      ' easy access to the map point clicked by the user
      Dim mapPointEventArgs As ESRI.ArcGIS.ADF.Web.UI.WebControls.MapPointEventArgs = CType(toolEventArgs, ESRI.ArcGIS.ADF.Web.UI.WebControls.MapPointEventArgs)
      ' Get the map point from the map point event arguments
      Dim adfPoint As ESRI.ArcGIS.ADF.Web.Geometry.Point = mapPointEventArgs.MapPoint

      ' Get the functionality of the resource that contains the layer on which you want to hyperlink
      Dim commonMapFunctionality As ESRI.ArcGIS.ADF.Web.DataSources.IMapFunctionality = adfMap.GetFunctionality("Server Resource")
      Dim gisResource As ESRI.ArcGIS.ADF.Web.DataSources.IGISResource = commonMapFunctionality.Resource

      ' Create query functionality from the resource
      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)

      ' Get the ids and names of the layers in the current that can be queried
      Dim layerIDs As String()
      Dim layerNames As String()
      queryFunctionality.GetQueryableLayers(Nothing, layerIDs, layerNames)

      ' Set the layer name on which you want to hyperlink
      Dim activeLayerName As String = "states"

      ' Iterate through the layer names until a match is found for
      ' activeLayerName.  Include a call to ToUpper() in the comparison
      ' to eliminate case sensitivity.
      Dim activeLayerID As String = Nothing
      Dim index As Integer = 0
      Do While index < layerNames.Length
        If layerNames(index).ToUpper() = activeLayerName.ToUpper() Then
          ' Get the layer id of the match found from the layer id array
          activeLayerID = layerIDs(index)
          Exit Do
        End If
        index += 1
      Loop

      ' Create a spatial filter and initialize its geometry with the point clicked
      Dim spatialFilter As ESRI.ArcGIS.ADF.Web.SpatialFilter = New ESRI.ArcGIS.ADF.Web.SpatialFilter()
      spatialFilter.Geometry = adfPoint

      Try
        ' Execute the query
        Dim resultDataTable As System.Data.DataTable = queryFunctionality.Query(commonMapFunctionality.Name, activeLayerID, spatialFilter)

        ' If no features returned, show alert
        If resultDataTable.Rows.Count < 1 Then
          Throw New System.Exception("No feature found")
        End If

        ' Name of field containing the term to the google search url
        Dim searchName As String = CStr(resultDataTable.Rows(0)("STATE_NAME"))

        ' If field contains no data, show alert
        If String.IsNullOrEmpty(searchName) Then
          Throw New System.Exception("Hyperlink field contains no data")
        End If

        ' Construct the JavaScript call to change the map cursor back to original
        Dim jsChangeCursor As String = "map.divObject.style.cursor = map.cursor"

        ' Create a callback result containing the JavaScript call and add to the
        ' map control's callback results collection
        Dim cursorCallbackResult As ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResult = ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResult.CreateJavaScript(jsChangeCursor)
        adfMap.CallbackResults.Add(cursorCallbackResult)

        ' Construct the JavaScript call to open a new browser window.  Any valid url can be used.
        Dim jsPopup As String = "window.open('http://www.google.com/search?q=" & searchName & "');"

        ' Create a callback result containing the JavaScript call and add to the
        ' map control's callback results collection
        Dim popupCallbackResult As ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResult = ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResult.CreateJavaScript(jsPopup)
        adfMap.CallbackResults.Add(popupCallbackResult)
      Catch exception As System.Exception
        ' If an error occurred, get the callback result from the ProcessError
        ' function and copy to the map control's callback results collection
        adfMap.CallbackResults.Add(Utility.GetErrorCallback(exception))
      End Try

    End Sub

    #End Region
  End Class

  Public Class PreviousExtent
        Implements ESRI.ArcGIS.ADF.Web.UI.WebControls.Tools.IMapServerCommandAction
    #Region "IMapServerCommandAction Members"

    Private Sub ServerAction(ByVal toolbarItemInfo As ESRI.ArcGIS.ADF.Web.UI.WebControls.Tools.ToolbarItemInfo) Implements ESRI.ArcGIS.ADF.Web.UI.WebControls.Tools.IServerAction.ServerAction
      Dim adfMap As ESRI.ArcGIS.ADF.Web.UI.WebControls.Map = CType(toolbarItemInfo.BuddyControls(0), ESRI.ArcGIS.ADF.Web.UI.WebControls.Map)

      Try
        ' Access to custom members in a page.  Implement custom interface in the Page.
        Dim baseToolbarRefresh As IBaseToolbarRefresh = CType(adfMap.Page, IBaseToolbarRefresh)

        ' A previous\next action is occurring
        ' Initial previous\next action to skip extent hashtable adjustment
        adfMap.Page.Session("previousNext") = True
        ' Subsequent map draw from previous\next action to skip extent hashtable adjustment
        adfMap.Page.Session("previousNextMapHandler") = True
        Dim extentsHashTable As System.Collections.Hashtable = Nothing

        ' If there is an extent history, continue
        If Not adfMap.Page.Session("extentHistory") Is Nothing Then
          ' Get the extent history
          extentsHashTable = CType(adfMap.Page.Session("extentHistory"), System.Collections.Hashtable)

          ' Get the current extent index.  If greater than 0, decrement the index
          ' and set the map extent to the previous extent in the extent history.               
          Dim extentIndex As Integer = CInt(Fix(adfMap.Page.Session("currentExtentIndex")))

          If extentIndex > 0 Then
            extentIndex -= 1
            adfMap.Page.Session("currentExtentIndex") = extentIndex
            adfMap.Extent = CType(extentsHashTable(extentIndex), ESRI.ArcGIS.ADF.Web.Geometry.Envelope)
          End If

          ' If the index is now less than or equal to 0, meaning there is not prior extent
          ' in the extent history, disable the previous extent command.
          If extentIndex <= 0 Then
            baseToolbarRefresh.RefreshToolbar("previousExtent", True)
          End If
        End If
        ' If there is an extent history, always enable the next extent command after the previous
        ' extent command is executed.
        baseToolbarRefresh.RefreshToolbar("nextExtent", False)
      Catch exception As System.Exception
        ' If an error occurred, get the callback result from the ProcessError
        ' function and copy to the map control's callback results collection
        adfMap.CallbackResults.Add(Utility.GetErrorCallback(exception))
      End Try
    End Sub

    #End Region
  End Class

  Public Class NextExtent
        Implements ESRI.ArcGIS.ADF.Web.UI.WebControls.Tools.IMapServerCommandAction
    #Region "IMapServerCommandAction Members"

    Private Sub ServerAction(ByVal toolbarItemInfo As ESRI.ArcGIS.ADF.Web.UI.WebControls.Tools.ToolbarItemInfo) Implements ESRI.ArcGIS.ADF.Web.UI.WebControls.Tools.IServerAction.ServerAction
      ' Get references to the map control and page via IBaseToolbarRefresh
      Dim adfMap As ESRI.ArcGIS.ADF.Web.UI.WebControls.Map = CType(toolbarItemInfo.BuddyControls(0), ESRI.ArcGIS.ADF.Web.UI.WebControls.Map)

      Try
        Dim baseToolbarRefresh As IBaseToolbarRefresh = CType(adfMap.Page, IBaseToolbarRefresh)

        ' A previous\next action is occurring
        ' Initial previous\next action to skip extent hashtable adjustment
        adfMap.Page.Session("previousNext") = True
        ' Subsequent map draw from previous\next action to skip extent hashtable adjustment
        adfMap.Page.Session("previousNextMapHandler") = True
        Dim extentsHashTable As System.Collections.Hashtable = Nothing

        ' If there is an extent history, continue
        If Not adfMap.Page.Session("extentHistory") Is Nothing Then
          ' Get the extent history and current extent index
          extentsHashTable = CType(adfMap.Page.Session("extentHistory"), System.Collections.Hashtable)
          Dim extentIndex As Integer = CInt(Fix(adfMap.Page.Session("currentExtentIndex")))

          ' Get the current extent index.  If index is less than the index of the last extent in extent history, 
          ' increment the index by 1 and set the map extent to the next extent in the extent history.
          If extentIndex < (extentsHashTable.Count - 1) Then
            extentIndex += 1
            adfMap.Page.Session("currentExtentIndex") = extentIndex
            adfMap.Extent = CType(extentsHashTable(extentIndex), ESRI.ArcGIS.ADF.Web.Geometry.Envelope)
          End If

          ' If the index greater than or equal to the index of the last extent in extent history,
          ' meaning there is not another extent to move to, disable the next extent command.
          If extentIndex >= (extentsHashTable.Count - 1) Then
            baseToolbarRefresh.RefreshToolbar("nextExtent", True)
          End If

          ' If there is an extent history, always enable the previous extent command after the 
          ' next extent command is executed.
          baseToolbarRefresh.RefreshToolbar("previousExtent", False)
        End If
      Catch exception As System.Exception
        ' If an error occurred, get the callback result from the ProcessError
        ' function and copy to the map control's callback results collection
        adfMap.CallbackResults.Add(Utility.GetErrorCallback(exception))
      End Try
    End Sub

    #End Region
  End Class

  Public Class Utility
    ' Constructs a callback result that will display an error message based on the passed-in
    ' exception
    Public Shared Function GetErrorCallback(ByVal exception As System.Exception) As ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResult
      ' Create a callback result to display an error message
      Dim jsAlertErrorMessage As String = GetJavaScriptErrorString(exception)
      Dim alertCallbackResult As ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResult = ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResult.CreateJavaScript(jsAlertErrorMessage)
      Return alertCallbackResult
    End Function

    ' Constructs JavaScript necessary to display an error message based on the passed-in exception.
    Public Shared Function GetJavaScriptErrorString(ByVal exception As System.Exception) As String
      ' Get the website's configuration file
      Dim webConfig As System.Configuration.Configuration = System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration(System.Web.HttpContext.Current.Request.ApplicationPath)

      ' Get the "compilation" section of the config file
      Dim compilationSection As System.Web.Configuration.CompilationSection = TryCast(webConfig.GetSection("system.web/compilation"), System.Web.Configuration.CompilationSection)

      ' If the config file's compilation section specifies debug mode, include 
      ' stack trace information in the error message.  Otherwise, just return 
      ' the exception message.
      Dim errorMessage As String = Nothing
      If (Not compilationSection Is Nothing) AndAlso (compilationSection.Debug) Then
        Dim stackTrace As String = exception.StackTrace.Replace("\", "\\")
        errorMessage = exception.Message & "\n\n" & stackTrace.Trim()
      Else
        errorMessage = exception.Message
      End If

      ' Create a callback result to display an error message
      Dim jsAlertException As String = "alert('" & errorMessage & "')"
      Return jsAlertException
    End Function
  End Class
End Namespace