Common Custom EditorTask
Common_CustomEditorTask_VBNet\CustomEditorTask_VBNet\CustomUtilities.vb
' Copyright 2011 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 CustomEditorTask_VBNet
  Friend Class CustomUtilities
    ' Get layer definition for layer currently being edited
    Friend Shared Function GetLayerDefinition(ByVal editor As ESRI.ArcGIS.ADF.ArcGISServer.Editor.Editor) As ESRI.ArcGIS.ADF.Web.UI.WebControls.LayerDefinition
      Dim mapResourceItem As ESRI.ArcGIS.ADF.Web.UI.WebControls.MapResourceItem = editor.Map.MapResourceManagerInstance.ResourceItems.Find(editor.MapResource.Name)

      Return mapResourceItem.GetUpdatedLayerDefinition(editor.SelectedLayerID.ToString())
    End Function

    ' Overload to allow function call with CustomEditor
    Friend Shared Function GetLayerDefinition(ByVal customEditor As CustomEditor) As ESRI.ArcGIS.ADF.Web.UI.WebControls.LayerDefinition
      Return GetLayerDefinition(CType(customEditor, ESRI.ArcGIS.ADF.ArcGISServer.Editor.Editor))
    End Function

    ' Get list of fields for currently selected layer
    Friend Shared Function GetFields(ByVal customEditor As CustomEditor) As String
      Dim fields As String = ""
      Dim i As Integer = 0
      Do While i < customEditor.CurrentLayerDefinition.LayerFormat.Fields.Count
        If customEditor.CurrentLayerDefinition.LayerFormat.Fields(i).Visible Then
          If customEditor.CurrentLayerDefinition.LayerFormat.Fields(i).Alias.Length > 0 Then
            fields &= customEditor.CurrentLayerDefinition.LayerFormat.Fields(i).Alias & ":::"
          Else
            fields &= customEditor.CurrentLayerDefinition.LayerFormat.Fields(i).Name & ":::"
          End If
        End If
        i += 1
      Loop
      fields = fields.Substring(0, fields.Length - 3)
      Return fields
    End Function

    ' Get list of fields for currently selected layer
    Friend Shared Function GetFields(ByVal customEditor As CustomEditor, ByVal fieldType As FieldType) As String
      Dim fields As String = ""
      Dim i As Integer = 0
      Do While i < customEditor.CurrentLayerDefinition.LayerFormat.Fields.Count
        Dim fieldInfo As ESRI.ArcGIS.ADF.Web.DataSources.FieldInfo = customEditor.CurrentLayerDefinition.LayerFormat.Fields(i)

        If customEditor.CurrentLayerDefinition.LayerFormat.Fields(i).Visible Then
          If (fieldType = FieldType.Numeric) AndAlso (fieldInfo.Type.ToLower() <> "double") AndAlso (fieldInfo.Type.ToLower() <> "int") AndAlso (fieldInfo.Type.ToLower() <> "long") AndAlso (fieldInfo.Type.ToLower() <> "int32") AndAlso (fieldInfo.Type.ToLower() <> "int16") AndAlso (fieldInfo.Type.ToLower() <> "int64") AndAlso (fieldInfo.Type.ToLower() <> "short") AndAlso (fieldInfo.Type.ToLower() <> "byte") AndAlso (fieldInfo.Type.ToLower() <> "float") AndAlso (fieldInfo.Type.ToLower() <> "single") Then
            i += 1
            Continue Do
          ElseIf (fieldType = FieldType.Text) AndAlso (fieldInfo.Type.ToLower() <> "string") AndAlso (fieldInfo.Type.ToLower() <> "char") Then
            i += 1
            Continue Do
          End If

          If customEditor.CurrentLayerDefinition.LayerFormat.Fields(i).Alias.Length > 0 Then
            fields &= customEditor.CurrentLayerDefinition.LayerFormat.Fields(i).Alias & ":::"
          Else
            fields &= customEditor.CurrentLayerDefinition.LayerFormat.Fields(i).Name & ":::"
          End If
        End If
        i += 1
            Loop
            If fields.Length > 0 Then
                fields = fields.Substring(0, fields.Length - 3)
            End If
            Return fields
        End Function

    ' Get sample values for passed-in field
    Friend Shared Function GetSampleValues(ByVal fieldAlias As String, ByVal editor As ESRI.ArcGIS.ADF.ArcGISServer.Editor.Editor) As String
      ' Get database field name for passed-in alias
      Dim fieldName As String = CustomUtilities.GetFieldName(fieldAlias, CType(editor, CustomEditor))

      ' Make sure field name was found
      If fieldName Is Nothing Then
        Return Nothing
      End If

      ' Make sure querying is supported for the current map resource
      Dim agsMapResourceLocal As ESRI.ArcGIS.ADF.Web.DataSources.ArcGISServer.MapResourceLocal = editor.MapResource
      Dim querySupported As Boolean = agsMapResourceLocal.SupportsFunctionality(GetType(ESRI.ArcGIS.ADF.Web.DataSources.IQueryFunctionality))
      If (Not querySupported) Then
        Return Nothing
      End If

      ' Create query functionality and query filter
      Dim queryFunctionality As ESRI.ArcGIS.ADF.Web.DataSources.IQueryFunctionality = CType(agsMapResourceLocal.CreateFunctionality(GetType(ESRI.ArcGIS.ADF.Web.DataSources.IQueryFunctionality), "query"), ESRI.ArcGIS.ADF.Web.DataSources.IQueryFunctionality)
      Dim adfQueryFilter As ESRI.ArcGIS.ADF.Web.QueryFilter = New ESRI.ArcGIS.ADF.Web.QueryFilter()
      adfQueryFilter.ReturnADFGeometries = False
      Dim customEditorTask As CustomEditorTask = CType(editor.EditorTask, CustomEditorTask)
      adfQueryFilter.MaxRecords = customEditorTask.SampleValueLimit
      adfQueryFilter.SubFields = New ESRI.ArcGIS.ADF.StringCollection(fieldName, Char.Parse(","))

      ' Execute query
      Dim resultsDataTable As System.Data.DataTable = queryFunctionality.Query(editor.MapFunctionality.Name, editor.SelectedLayerID.ToString(), adfQueryFilter)

      ' Make sure results were returned
      If resultsDataTable Is Nothing Then
        Return Nothing
      End If

      ' Retrieve results from table and format into results string
      Dim results As String = ":::"

      ' Replace periods in field name if necessary
      If fieldName <> resultsDataTable.Columns(0).ColumnName Then
        fieldName = fieldName.Replace(".", "_")
      End If

      Dim i As Integer = 0
      Do While i < resultsDataTable.Rows.Count
        ' Get field value from current row
        Dim result As String = resultsDataTable.Rows(i)(fieldName).ToString()
        ' Make sure value is not already in results string and is not empty
        If (results.IndexOf(System.String.Format(":::{0}:::", result)) < 0) AndAlso (result <> "") AndAlso (result <> " ") AndAlso (result <> "NaN") AndAlso (Not result Is Nothing) Then
          results &= System.String.Format("{0}:::", resultsDataTable.Rows(i)(fieldName).ToString())
        End If
        i += 1
      Loop
      If results.Length > 5 Then
        results = results.Substring(3, results.Length - 6)
      End If

      Return results
    End Function

    ' Get actual database field name for passed-in alias
    Friend Shared Function GetFieldName(ByVal fieldAlias As String, ByVal editor As CustomEditor) As String
      'find field name based on alias
      Dim fieldName As String = Nothing
      Dim i As Integer = 0
      Do While i < editor.CurrentLayerDefinition.LayerFormat.Fields.Count
        If editor.CurrentLayerDefinition.LayerFormat.Fields(i).Alias = fieldAlias Then
          fieldName = editor.CurrentLayerDefinition.LayerFormat.Fields(i).Name
          Exit Do
        End If
        i += 1
      Loop

      ' If no matching alias was found, check whether passed-in alias
      ' matches an actual database field name
      i = 0
      Do While i < editor.CurrentLayerDefinition.LayerFormat.Fields.Count
        If editor.CurrentLayerDefinition.LayerFormat.Fields(i).Name = fieldAlias Then
          fieldName = editor.CurrentLayerDefinition.LayerFormat.Fields(i).Name
          Exit Do
        End If
        i += 1
      Loop

      Return fieldName
    End Function

    ' Replace field aliases in passed-in string with corresponding actual database field names
    Public Shared Function ReplaceAliases(ByVal fieldAliasesString As String, ByVal customEditor As CustomEditor) As String
      Dim fieldAliasesArray As String() = fieldAliasesString.Split(";"c)
      Dim fieldNamesString As String = ""
      Dim i As Integer = 0
      Do While i < fieldAliasesArray.Length
        fieldNamesString &= CustomUtilities.GetFieldName(fieldAliasesArray(i), customEditor)
        If i < fieldAliasesArray.Length - 1 Then
          fieldNamesString &= ";"
        End If
        i += 1
      Loop

      Return fieldNamesString
    End Function

    ' Execute query and return feature ids from results
    Public Shared Function DoQuery(ByVal query As String, ByVal editor As ESRI.ArcGIS.ADF.ArcGISServer.Editor.Editor) As Integer()
      Dim agsMapResourceLocal As ESRI.ArcGIS.ADF.Web.DataSources.ArcGISServer.MapResourceLocal = editor.MapResource

      ' Make sure querying is supported for the current map resource
      Dim querySupported As Boolean = agsMapResourceLocal.SupportsFunctionality(GetType(ESRI.ArcGIS.ADF.Web.DataSources.IQueryFunctionality))

      If (Not querySupported) Then
        Return New Integer(){}
      End If

      ' Create query functionality and query filter
      Dim queryFunctionality As ESRI.ArcGIS.ADF.Web.DataSources.IQueryFunctionality = CType(agsMapResourceLocal.CreateFunctionality(GetType(ESRI.ArcGIS.ADF.Web.DataSources.IQueryFunctionality), "query"), ESRI.ArcGIS.ADF.Web.DataSources.IQueryFunctionality)
      Dim adfQueryFilter As ESRI.ArcGIS.ADF.Web.QueryFilter = New ESRI.ArcGIS.ADF.Web.QueryFilter()
      adfQueryFilter.ReturnADFGeometries = False
      adfQueryFilter.MaxRecords = editor.EditorTask.SelectionLimit
      adfQueryFilter.WhereClause = query

      ' Execute query
      Dim dtResults As System.Data.DataTable = queryFunctionality.Query(editor.MapFunctionality.Name, editor.SelectedLayerID.ToString(), adfQueryFilter)

      ' Make sure results were returned
      If dtResults Is Nothing Then
        Return New Integer(){}
      End If

      ' copy object IDs of results to array
      Dim idSet As Integer() = New Integer(dtResults.Rows.Count - 1){}
      Dim i As Integer = 0
      Do While i < dtResults.Rows.Count
        idSet(i) = CInt(Fix(dtResults.Rows(i)(editor.FeatureLayer.FeatureClass.OIDFieldName)))
        i += 1
      Loop

      Return idSet
    End Function

    ' Update the passed-in selection based on the selection mode
    Friend Shared Function UpdateSelection(ByVal currentSelection As Integer(), ByVal newSelection As Integer(), <System.Runtime.InteropServices.Out()> ByRef selectionChanged As Boolean, ByVal editorTask As ESRI.ArcGIS.ADF.ArcGISServer.Editor.EditorTask) As System.Collections.Generic.List(Of Integer)
      Dim selectedIDsList As System.Collections.Generic.List(Of Integer) = New System.Collections.Generic.List(Of Integer)()
      selectionChanged = False

      ' Get the selection limit
      Dim selectionLimit As Integer = editorTask.SelectionLimit

      Select Case editorTask.FeatureSelectionMode
        Case ESRI.ArcGIS.ADF.ArcGISServer.Editor.FeatureSelectionMode.CreateNew 
          ' Add IDs of newly selected features to selection list
          If newSelection.Length > 0 Then
            If newSelection.Length > selectionLimit Then
              System.Array.Resize(newSelection, selectionLimit)
            End If
            selectedIDsList.AddRange(newSelection)
            selectionChanged = True
          Else
            If Not currentSelection Is Nothing AndAlso currentSelection.Length > 0 Then
              selectionChanged = True
            End If
          End If

        Case ESRI.ArcGIS.ADF.ArcGISServer.Editor.FeatureSelectionMode.Add
          ' Add IDs of currently selected features to selection list
          If Not currentSelection Is Nothing Then
            selectedIDsList.AddRange(currentSelection)
          End If

          ' Resize list of newly selected ids to be within selection limit
          If newSelection.Length > selectionLimit Then
            System.Array.Resize(newSelection, selectionLimit)
          End If

          Dim numAdded As Integer = 0

          ' Add newly selected IDs to current IDs
          For Each i As Integer In newSelection
            If (Not selectedIDsList.Contains(i)) Then
              selectedIDsList.Add(i)
                            numAdded = numAdded + 1
                            If numAdded = selectionLimit Then
                                Exit For
                            End If
            End If
          Next i
          ' Set selection changed flag based on whether any IDs were added to selection
          selectionChanged = numAdded > 0

        Case ESRI.ArcGIS.ADF.ArcGISServer.Editor.FeatureSelectionMode.Remove
          ' Add all currently selected IDs to selection
          If Not currentSelection Is Nothing Then
            selectedIDsList.AddRange(currentSelection)
          End If

          ' Compare newly selected IDs to selection (currently selected IDs)
          ' and remove any newsly selected IDs already selected
          For Each i As Integer In newSelection
            If selectedIDsList.Contains(i) Then
              selectedIDsList.Remove(i)
              selectionChanged = True
            End If
          Next i

        Case ESRI.ArcGIS.ADF.ArcGISServer.Editor.FeatureSelectionMode.Toggle
          ' Exit if no new features selected
          If newSelection.Length = 0 Then
            Exit Select
          End If

          selectionChanged = True
          ' Set featuresToAddCount to number of newly selected features or selection limit 
          ' depending on whether number of newly selected features exceeds limit
          Dim featuresToAddCount As Integer
          If selectionLimit < newSelection.Length Then
            featuresToAddCount = selectionLimit
          Else
            featuresToAddCount = newSelection.Length
          End If

          ' Add IDs of currently selected features to selection
          If Not currentSelection Is Nothing Then
            selectedIDsList.AddRange(currentSelection)
          End If

          ' Check to see whether each newly selected feature is already selected.
          ' If so, remove it from selection.  if not, add it to selection.
          Dim i As Integer = 0
          Do While i < featuresToAddCount
            Dim currentID As Integer = newSelection(i)
            Dim index As Integer = selectedIDsList.IndexOf(currentID)
            If index = -1 Then
              selectedIDsList.Add(currentID)
            Else
              selectedIDsList.RemoveAt(index)
            End If
            i += 1
          Loop
      End Select

      Return selectedIDsList
    End Function

    Friend Shared Function FindControl(ByVal controlID As String, ByVal parentControl As System.Web.UI.Control) As System.Web.UI.Control
      If parentControl.ID = controlID Then
        Return parentControl
      End If

      If Not parentControl.Controls Is Nothing Then
        For Each childControl As System.Web.UI.Control In parentControl.Controls
          Dim foundControl As System.Web.UI.Control = FindControl(controlID, childControl)
          If Not foundControl Is Nothing Then
            Return foundControl
          End If
        Next childControl
      End If

      Return Nothing
    End Function

    Friend Enum FieldType
      All
      Text
      Numeric
    End Enum
  End Class
End Namespace