Common Custom tasks
Common_CustomTasks_VBNet\OptimizeTask_VBNet\OptimizeTask.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 OptimizeTask_VBNet
  ' Specifies the default markup inserted when the task is dragged from the toolbox onto a
  ' page in Visual Studio
  <System.Web.UI.ToolboxData("<{0}:OptimizeTask_VBNet runat=""server"" Width=""100px"" BorderWidth=""1px""><TaskResultsContainers><esri:BuddyControl Name=""TaskResults1"" /></TaskResultsContainers> </{0}:OptimizeTask_VBNet>")> _
  Public Class OptimizeTask
    Inherits ESRI.ArcGIS.ADF.Web.UI.WebControls.FloatingPanelTask
    #Region "Instance Variable Declarations"

    Private _handleCallbackButton As CustomCallbackButton
    Private _handlePartialPostBackButton As System.Web.UI.WebControls.Button
    Private _taskResults As ESRI.ArcGIS.ADF.Web.UI.WebControls.TaskResults
    Private m_taskTextKey As String = "textValue"

    #End Region

    #Region "Instance Properties"

    Public Property ButtonText() As String
      Get
        ' Attempt to retrieve the button text from state
        Dim buttonTextObject As Object = StateManager.GetProperty("buttonText")
        ' If no button text was stored in state, return the default value.  Otherwise,
        ' return the text as a string.
        If (buttonTextObject Is Nothing) Then
          Return "Execute"
        Else
          Return TryCast(buttonTextObject, String)
        End If
      End Get
      Set
        ' Store the passed-in value in state
        StateManager.SetProperty("buttonText", Value)
      End Set
    End Property

    ' Convenient access to the first TaskResults control in the Task's TaskResultsContainers collection
    Friend ReadOnly Property TaskResultsInstance() As ESRI.ArcGIS.ADF.Web.UI.WebControls.TaskResults
      Get
        ' Retrieve the TaskResults control if it has not already been
        If (_taskResults Is Nothing) AndAlso (Not Me.TaskResultsContainers(0) Is Nothing) Then
          _taskResults = tryCast(ESRI.ArcGIS.ADF.Web.UI.WebControls.Utility.FindControl(Me.TaskResultsContainers(0).Name, Me.Page), ESRI.ArcGIS.ADF.Web.UI.WebControls.TaskResults)
        End If

        Return _taskResults
      End Get
    End Property

    #End Region

    ' Configures the task's interface - NOTE: AsyncOptimizer is used in this method 
    Protected Overrides Overloads Sub CreateChildControls()
      Controls.Clear()
      MyBase.CreateChildControls()

      ' Determine calling control if an async request.  
      ' If not this task or child component within this task, skip creating
      ' child controls.
      Dim asyncOptimizer As AsyncOptimizer = New AsyncOptimizer(Me)
      If (Not asyncOptimizer.RequiresChildControls) Then
        Return
      End If

      ' Clear list of task child controls that make async calls (readd controls if necessary below) 
      asyncOptimizer.ChildControlsHandlingAsyncCalls.Clear()

      ' If there is no ScriptManager on the page, initialize and add custom callback button to the task.
      ' Otherwise, add a partial postback button.  Both controls will initiate an async request that 
      ' does not execute the task, but is processed by an event on the control.  As a result,
      ' task content must be recreated to process the request.    
      If Me.ScriptManager Is Nothing Then
'        #Region "Custom Callback Button Instantiation"

        ' Initialize a custom callback button and add it to the task's controls collection
        _handleCallbackButton = New CustomCallbackButton()
        _handleCallbackButton.ID = "CallbackButton"
        _handleCallbackButton.Text = "Handle Callback"
        _handleCallbackButton.UseSubmitBehavior = False
        _handleCallbackButton.TaskInstance = Me

        Controls.Add(_handleCallbackButton)
'        #End Region

        ' Register this control with the AsyncOptimizer as a control that may initiate an async request.
        ' If it does, CreateChildControls in this task will execute normally.  Note, the list of control ids
        ' is stored in session.
        asyncOptimizer.ChildControlsHandlingAsyncCalls.Add(_handleCallbackButton.UniqueID)
      Else
'        #Region "Partial PostBack Button Instantiation"

        ' Initialize a button that will trigger a partial postback
        _handlePartialPostBackButton = New System.Web.UI.WebControls.Button()
        _handlePartialPostBackButton.ID = "partialPostBackButton"
        _handlePartialPostBackButton.Text = "Handle Partial PostBack"
        '_handlePartialPostBackButton.UseSubmitBehavior = false;

        ' Wire a handler for the button's click event
        AddHandler _handlePartialPostBackButton.Click, AddressOf HandlePartialPostBackButton_Click

        ' Regiester the button as an asyncrhonous postback control so it triggers a partial postback
        ' when clicked
        ScriptManager.RegisterAsyncPostBackControl(_handlePartialPostBackButton)

        ' Add the button to the task's controls collection
        Controls.Add(_handlePartialPostBackButton)

'        #End Region

        ' Register this control with the AsyncOptimizer as a control that may initiate an async request.
        ' If it does, CreateChildControls in this task will execute normally.  Note, the list of control ids
        ' is stored in session.
        asyncOptimizer.ChildControlsHandlingAsyncCalls.Add(_handlePartialPostBackButton.UniqueID)

      End If

'      #Region "Textbox containing value to pass during task execution"
      ' Create a textbox and add it to the task's controls collection
      Dim textBox As System.Web.UI.WebControls.TextBox = New System.Web.UI.WebControls.TextBox()
      textBox.ID = "PostBackTaskTextBox"
      Controls.Add(textBox)

      ' Define an argument to return when executing the task
      Dim customArguments As String = String.Format("'{0}=' + ESRI.ADF.System.escapeForCallback($get('{1}').value)", m_taskTextKey,textBox.ClientID)
'      #End Region

'      #Region "Button Initiating Task Execution via Web ADF Task Framework"

      ' Create a button for task execution
      Dim executeTaskButton As System.Web.UI.WebControls.Button = New System.Web.UI.WebControls.Button()
      executeTaskButton.Text = "Execute Task"

      ' Construct JavaScript that calls the Web ADF's executeTask function.  This will initiate
      ' a callback that invokes the task's ExecuteTask method on the server.
      Dim executeTaskJavaScript As String = String.Format("ESRI.ADF.Tasks.executeTask({0}, ""{1}"");return false;", customArguments, CallbackFunctionString)

      ' Wire the JavaScript to execute when the button is clicked
      executeTaskButton.OnClientClick = executeTaskJavaScript

      ' Add the button to the task's controls colleciton
      Controls.Add(executeTaskButton)


'      #End Region
    End Sub

    Protected Overrides Overloads Sub OnPreRender(ByVal e As System.EventArgs)
      MyBase.OnPreRender(e)
'      #Region "Partial PostBack Response Handling"

      ' Create the JavaScript necessary to pass the result of a partial postback to the Web ADF
      ' JavaScript library's processCallbackResult function
      Dim scriptKeyCustom As String = "customDataItemScript"
      If (Not Me.Page.ClientScript.IsStartupScriptRegistered(Me.GetType(), scriptKeyCustom)) AndAlso Not Me.ScriptManager Is Nothing Then
        Dim processDataItemJavaScript As String = "" & ControlChars.CrLf & "                " & ControlChars.CrLf & "                        function onLoadFunction(){{" & ControlChars.CrLf & "                          Sys.WebForms.PageRequestManager.getInstance().add_pageLoading(AsyncResponseHandler);" & ControlChars.CrLf & "                        }}" & ControlChars.CrLf & ControlChars.CrLf & "                        function AsyncResponseHandler(sender, args) {{" & ControlChars.CrLf & "                          var dataItems = args.get_dataItems();" & ControlChars.CrLf & "                          if (dataItems['{0}'] != null)" & ControlChars.CrLf & "                            ESRI.ADF.System.processCallbackResult(dataItems['{0}']);" & ControlChars.CrLf & "                        }}" & ControlChars.CrLf & ControlChars.CrLf & "                        Sys.Application.add_init(onLoadFunction);"
        processDataItemJavaScript = String.Format(processDataItemJavaScript, Me.Page.ClientID)

        ' Register the script as a startup script so the result handling code is wired during
        ' applicaton initialization
        Me.Page.ClientScript.RegisterStartupScript(Me.GetType(), scriptKeyCustom, processDataItemJavaScript, True)

      End If

'      #End Region

    End Sub


    #Region "Task Overrides"

    ' Fires first when the task is executed.  Retrieves the values needed to perform the necessary
    ' server-side action.
    Public Overrides Overloads Function GetCallbackResult() As String
      ' Set the task's Input member to the value of the task's textbox 
      Dim keyValColl As System.Collections.Specialized.NameValueCollection = ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackUtility.ParseStringIntoNameValueCollection(CallbackEventArgument)
      Input = keyValColl(m_taskTextKey)
      Return MyBase.GetCallbackResult()
    End Function

    ' Fires second when the task is executed.  Performs the necessary server-side logic.
    Public Overrides Overloads Sub ExecuteTask()
      ' Clear any left-over task results and make sure task input exists
      Results = Nothing
      If Input Is Nothing Then
      Return
      End If

      ' Get the task's textbox value from the Input property
      Dim textBoxValue As String = TryCast(Input, String)

      ' Format the heading of the task result to display the current time on the server
      Dim taskResultHeading As String = String.Format("The time on the server is {0}", System.DateTime.Now.ToShortTimeString())

      ' Format the detail of the task result to display the value of the task's textbox when
      ' the task was executed
      Dim taskResultDetail As String = String.Format("The value in the text box is: {0}", textBoxValue)

      ' Create a simple task result with the heading and detail
      Dim simpleTaskResult As ESRI.ArcGIS.ADF.Web.UI.WebControls.SimpleTaskResult = New ESRI.ArcGIS.ADF.Web.UI.WebControls.SimpleTaskResult(taskResultHeading, taskResultDetail)

      ' Set the task's Results property to the simple task result.  The contents of this property
      ' will be passed to the task's results container.
      Results = simpleTaskResult

    End Sub

    ' Overriden to return an empty list, indicating that the task has no resource dependencies.
    Public Overrides Overloads Function GetGISResourceItemDependencies() As System.Collections.Generic.List(Of ESRI.ArcGIS.ADF.Web.UI.WebControls.GISResourceItemDependency)
      Dim list As System.Collections.Generic.List(Of ESRI.ArcGIS.ADF.Web.UI.WebControls.GISResourceItemDependency) = New System.Collections.Generic.List(Of  ESRI.ArcGIS.ADF.Web.UI.WebControls.GISResourceItemDependency)()
      Return list
    End Function

    #End Region

    #Region "UI Event Handlers - HandlePartialPostBackButton_Click"

    ' Fires when the Handle Partial PostBack button is clicked
    Private Sub HandlePartialPostBackButton_Click(ByVal sender As Object, ByVal e As System.EventArgs)
      ' Zoom the map
      If Not TaskResultsInstance.MapInstance Is Nothing Then
        TaskResultsInstance.MapInstance.Zoom(2)
      End If

      ' Copy the map's callback results to the task results container's callback results collection
      TaskResultsInstance.CallbackResults.CopyFrom(TaskResultsInstance.MapInstance.CallbackResults)

      ' Register the task results container's callback results as a data item.  This will pass the
      ' callback results to the client-side AsyncResponseHandler function that was registered in
      ' OnPreRender.  This function, in turn, will pass the callback results to the Web ADF's 
      ' processCallbackResults function.
      Me.ScriptManager.RegisterDataItem(Page, TaskResultsInstance.CallbackResults.ToString(), False)
    End Sub

    #End Region
  End Class

  Public Class CustomCallbackButton
    Inherits System.Web.UI.WebControls.Button
    Implements System.Web.UI.ICallbackEventHandler
    #Region "Instance Variable Declarations"

    Private _callbackArg As String
    Private _task As OptimizeTask

    #End Region

    Protected Overrides Sub OnPreRender(ByVal e As System.EventArgs)
      MyBase.OnPreRender(e)

'      #Region "Custom Callback Button Click Handling"

      ' Get the JavaScript syntax for invoking a callback to the callback button
      Dim callbackInvocationString As String = Page.ClientScript.GetCallbackEventReference(Me, "argument", "processCallbackResult", "context")

      ' Construct JavaScript to create an argument string containing the browser's dimensions
      ' and execute a callback to pass the argument to the server.
      Dim callbackJavaScript As String = "" & ControlChars.CrLf & "                        var argument = 'callbackArgument=ZoomMap';" & ControlChars.CrLf & "                        var context = null;" & ControlChars.CrLf & "                        {0};" & ControlChars.CrLf & "                        return;" & ControlChars.CrLf & "                    "
      ' Substitute the callback invocation into the callback packaging JavaScript
      callbackJavaScript = String.Format(callbackJavaScript, callbackInvocationString)

      ' Wire the script to the callback button's click event
      OnClientClick = callbackJavaScript

'      #End Region
    End Sub


    #Region "ICallbackEventHandler Members - RaiseCallbackEvent, GetCallbackResult"

    ' The first method to execute on the server when a callback is invoked from the client.  The string
    ' containing the callback's parameters is passed to this method.
    Public Sub RaiseCallbackEvent(ByVal eventArgument As String) Implements System.Web.UI.ICallbackEventHandler.RaiseCallbackEvent
      ' Store the callback argument string in an instance variable for reference in GetCallbackResult
      _callbackArg = eventArgument
    End Sub

    ' Fires when a callback string referencing a CustomCallbackButton instance is invoked from the client.  
    ' In the PostBackTask implementation above, the JavaScript needed to do that is wired to a 
    ' CustomCallbackButton instance in the OnPreRender method.
    Public Function GetCallbackResult() As String Implements System.Web.UI.ICallbackEventHandler.GetCallbackResult
      ' Use the Web ADF's callback parsing utility to split the callback argument string into a 
      ' collection of name-value pairs.
      Dim callbackArgsCollection As System.Collections.Specialized.NameValueCollection = ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackUtility.ParseStringIntoNameValueCollection(_callbackArg)

      ' Get the callback argument from the collection
      Dim callbackArguments As String = callbackArgsCollection("callbackArgument")

      If (Not String.IsNullOrEmpty(callbackArguments)) Then
        If callbackArguments = "ZoomMap" Then
          ' Zoom the map buddied to the callback button's parent PostBackTask
          If Not Me.TaskInstance.TaskResultsInstance.MapInstance Is Nothing Then
            Me.TaskInstance.TaskResultsInstance.MapInstance.Zoom(2)
          End If

          ' Copy the map's callback results to the task results container's results collection
          Me.TaskInstance.TaskResultsInstance.CallbackResults.CopyFrom(Me.TaskInstance.TaskResultsInstance.MapInstance.CallbackResults)
        End If
      End If

      Return TaskInstance.TaskResultsInstance.CallbackResults.ToString()
    End Function

    #End Region

    #Region "Instance Properties - PostBackTaskInstance"

    ' Provides access to the parent task
    Friend Property TaskInstance() As OptimizeTask
      Get
        Return _task
      End Get
      Set
        _task = Value
      End Set
    End Property

    #End Region
  End Class
End Namespace