Common_TaskResults_VBNet\TaskResultsWebSite\App_Code\TabularResultsTask.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 ESRI.ADF.Samples.CustomTasks Public Class TabularResultsTask Inherits ESRI.ArcGIS.ADF.Tasks.QueryAttributesTask #Region "Instance Variable Declarations" ' Stores a reference to the buddied TaskResults Control Private m_taskResults As ESRI.ArcGIS.ADF.Web.UI.WebControls.TaskResults = Nothing ' Tracks whether the current page request has routed through ExecuteTask Private _taskExecuted As Boolean = False ' Stores a reference to the custom context menu that provides an option to view the ' results table Private _graphicsLayerContextMenu As ESRI.ArcGIS.ADF.Web.UI.WebControls.ContextMenu #End Region #Region "ASP.NET WebControl Life Cycle Event Handlers" ' Creates the custom task results context menu and wires task results control event handlers Protected Overrides Sub CreateChildControls() MyBase.CreateChildControls() Me.CreateTaskResultsPanelContextMenu() ' Add a handler to the buddied TaskResults Control's NodeAdded event AddHandler TaskResultsInstance.NodeAdded, AddressOf TaskResultsInstance_NodeAdded AddHandler TaskResultsInstance.NodeRemoved, AddressOf TaskResultsInstance_NodeRemoved End Sub ' Registers the client script needed by TaskResultsPanel. We do this here since no ' TaskResultsPanel is being created during application start-up. Protected Overrides Sub Render(ByVal writer As System.Web.UI.HtmlTextWriter) MyBase.Render(writer) ESRI.ADF.Samples.CustomTasks.TaskResultsPanel.RegisterScripts(Me) End Sub #End Region #Region "Web ADF Control Event Handlers" ' Retrieves the results graphics layer and uses it to initialize a TaskResultsPanel. Done here for extended tasks ' because the results graphics layer available in ExecuteTask is replaced during subsequent task result node creation. Private Sub TaskResultsInstance_NodeAdded(ByVal sender As Object, ByVal args As ESRI.ArcGIS.ADF.Web.UI.WebControls.TreeViewPlusNodeEventArgs) If Me._taskExecuted Then ' Get the GraphicsLayerNode that is an ancestor or descendant of the current node Dim graphicsLayerNode As ESRI.ArcGIS.ADF.Web.UI.WebControls.GraphicsLayerNode = Me.GetRelatedGraphicsLayerNode(args.Node) ' Make sure a GraphicsLayerNode was found If Not graphicsLayerNode Is Nothing Then ' Create the TaskResultsPanel that will be used to display results Dim taskResultsPanelID As String = String.Format("{0}_TaskResultsPanel", graphicsLayerNode.NodeID) Dim taskResultsPanelTitle As String = String.Format("{0} - {1} {2}", Me.Title, Me.PredefinedQuery.FormEntries(0).LabelText, Me.PredefinedQuery.FormEntries(0).UserInput) Dim taskResultsPanel As ESRI.ADF.Samples.CustomTasks.TaskResultsPanel = Me.CreateTaskResultsPanel(taskResultsPanelID, taskResultsPanelTitle) ' When a Web ADF FloatingPanel is rendered during an asynchronous request, the ADF automatically creates ' a callback result that includes a call to the private client-side function _checkDock. In cases where the ' FloatingPanel does not have a docking container, this interferes with the FloatingPanel's initialization. ' So we remove that callback result here. Dim checkDockJavaScript As String = String.Format("$find('{0}')._checkDock();", taskResultsPanel.ClientID) Dim callbackResultToRemove As ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResult = Nothing For Each callbackResult As ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResult In taskResultsPanel.CallbackResults If TryCast(callbackResult.Parameters(0), String) = checkDockJavaScript Then callbackResultToRemove = callbackResult Exit For End If Next callbackResult If Not callbackResultToRemove Is Nothing Then taskResultsPanel.CallbackResults.Remove(callbackResultToRemove) End If ' Get the name of the resource containing the results GraphicsLayer Dim resourceName As String = graphicsLayerNode.Layer.DataSet.DataSetName ' Construct the client-side GraphicFeatureGroup ID of the results graphics layer. Note that this is only necessary ' for extended out-of-the-box tasks. Otherwise, Map::GetGraphicsLayerClientID or MapTips::GraphicsLayerClientID can ' be used. Dim featureGraphicsLayer As ESRI.ArcGIS.ADF.Web.Display.Graphics.FeatureGraphicsLayer = TryCast(graphicsLayerNode.Layer, ESRI.ArcGIS.ADF.Web.Display.Graphics.FeatureGraphicsLayer) Dim graphicsLayerClientID As String = String.Format("{0}_{1} {2} Results_{3}", Me.TaskResultsInstance.MapInstance.ClientID, Me.TaskResultsInstance.ClientID, featureGraphicsLayer.FeatureType.ToString(), graphicsLayerNode.Layer.TableName) ' Call SetLayer to associate the TaskResultsPanel with the GraphicsLayer taskResultsPanel.SetLayer(featureGraphicsLayer, resourceName, Me.TaskResultsInstance.Map, graphicsLayerClientID) ' Call ShowFloatingPanel to display the results panel taskResultsPanel.ShowFloatingPanel() ' Associate the context menu with the "view table" option to the graphics layer node Me.TaskResultsInstance.SetupContextMenu(_graphicsLayerContextMenu, graphicsLayerNode) ' Copy the results panel's callback results to the task's results collection so changes made to the ' panel requiring client-side handling are processed Me.CallbackResults.CopyFrom(taskResultsPanel.CallbackResults) ' Reset the flag indicating whether a new TaskResultsPanel needs to be created Me._taskExecuted = False End If End If End Sub Public Overrides Function GetCallbackResult() As String Return MyBase.GetCallbackResult() End Function ' Checks whether the removed node is a GraphicsLayerNode and removes any associated TaskResultsPanel if so Private Sub TaskResultsInstance_NodeRemoved(ByVal sender As Object, ByVal args As ESRI.ArcGIS.ADF.Web.UI.WebControls.TreeViewPlusNodeRemovedEventArgs) ' Call method to retrieve a GraphicsLayerNode that is the child of the current node. Note this method ' will also check whether the current node is a GraphicsLayerNode Dim graphicsLayerNode As ESRI.ArcGIS.ADF.Web.UI.WebControls.GraphicsLayerNode = Me.FindChildGraphicsLayerNode(args.Node) ' Check whether a GraphicsLayerNode was found If Not graphicsLayerNode Is Nothing Then ' Construct JavaScript to find the TaskResultsPanel corresponding to the GraphicsLayerNode and ' destroy it. Dim taskResultsPanelClientID As String = String.Format("{0}_{1}_TaskResultsPanel", Me.ClientID, graphicsLayerNode.NodeID) Dim disposeResultsPanelJavaScript As String = "" & ControlChars.CrLf & " var taskResultsPanel = $find('{0}');" & ControlChars.CrLf & " if (taskResultsPanel)" & ControlChars.CrLf & " {{" & ControlChars.CrLf & " taskResultsPanel.hide(false);" & ControlChars.CrLf & " taskResultsPanel.dispose();" & ControlChars.CrLf & " }}" & ControlChars.CrLf & " var element = $get('{0}');" & ControlChars.CrLf & " if (element)" & ControlChars.CrLf & " element.parentNode.removeChild(element);" disposeResultsPanelJavaScript = String.Format(disposeResultsPanelJavaScript, taskResultsPanelClientID) ' Encapsulate the JavaScript in a callback result and add it to the task's collection of CallbackResults Dim disposeResultsPanelCallbackResult As ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResult = ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResult.CreateJavaScript(disposeResultsPanelJavaScript) Me.TaskResultsInstance.CallbackResults.Add(disposeResultsPanelCallbackResult) End If End Sub ' Fires when the custom GraphicLayer context menu is closed. Private Sub GraphicsLayerContextMenu_Dismissed(ByVal sender As Object, ByVal args As ESRI.ArcGIS.ADF.Web.UI.WebControls.ContextMenuDismissedEventArgs) Me.TaskResultsInstance.ContextMenuDismissed(_graphicsLayerContextMenu, args) End Sub ' Fires when an item on the custom GraphicsLayer context menu is clicked Private Sub GraphicsLayerContextMenu_ItemClicked(ByVal sender As Object, ByVal args As ESRI.ArcGIS.ADF.Web.UI.WebControls.ContextMenuItemEventArgs) ' Get the node on which the context menu was displayed Dim graphicsLayerNode As ESRI.ArcGIS.ADF.Web.UI.WebControls.GraphicsLayerNode = TryCast(TaskResultsInstance.Nodes.FindByNodeID(args.Context), ESRI.ArcGIS.ADF.Web.UI.WebControls.GraphicsLayerNode) ' Check the text of the item clicked Select Case args.Item.Text Case "Zoom To Selected Features" If graphicsLayerNode Is Nothing OrElse Me.MapInstance Is Nothing Then Return End If Dim hasFeaturesSelected As Boolean = False ' Get the GraphicsLayer associated with the node Dim graphicsLayer As ESRI.ArcGIS.ADF.Web.Display.Graphics.GraphicsLayer = graphicsLayerNode.Layer ' Declare an envelope to store the combined extent of all features in the layer Dim adfEnvelope As ESRI.ArcGIS.ADF.Web.Geometry.Envelope = New ESRI.ArcGIS.ADF.Web.Geometry.Envelope() ' Loop through the rows (i.e. features) of the graphics layer, adding the envelope of each to the ' combined extent envelope Dim i As Integer = 0 Do While i < graphicsLayer.Rows.Count If CBool(graphicsLayer.Rows(i)(graphicsLayer.IsSelectedColumn)) Then hasFeaturesSelected = True Dim rowGeometry As ESRI.ArcGIS.ADF.Web.Geometry.Geometry = graphicsLayer.GeometryFromRow(graphicsLayer.Rows(i)) adfEnvelope.Union(rowGeometry) End If i += 1 Loop If (Not hasFeaturesSelected) Then Return End If ' If combined envelope width or height is zero, zoom in the amount specified by the ' ZoomToPointFactor property If adfEnvelope.Width = 0 OrElse adfEnvelope.Height = 0 Then Dim adfPoint As ESRI.ArcGIS.ADF.Web.Geometry.Point = New ESRI.ArcGIS.ADF.Web.Geometry.Point(adfEnvelope.XMax, adfEnvelope.YMax) Dim fullExtentEnvelope As ESRI.ArcGIS.ADF.Web.Geometry.Envelope = Me.MapInstance.GetFullExtent() Dim widthMargin As Double = (fullExtentEnvelope.Width / TaskResultsInstance.ZoomToPointFactor) / 2 Dim heightMargin As Double = (fullExtentEnvelope.Height / TaskResultsInstance.ZoomToPointFactor) / 2 Dim zoomToEnvelope As ESRI.ArcGIS.ADF.Web.Geometry.Envelope = New ESRI.ArcGIS.ADF.Web.Geometry.Envelope() zoomToEnvelope.XMax = adfPoint.X + widthMargin zoomToEnvelope.XMin = adfPoint.X - widthMargin zoomToEnvelope.YMax = adfPoint.Y + heightMargin zoomToEnvelope.YMin = adfPoint.Y - heightMargin Me.MapInstance.Extent = zoomToEnvelope Else ' Apply the combined feature extent to the map Me.MapInstance.Extent = adfEnvelope End If ' Copy the map's callback results to the context menu so the extent change is processed on the client _graphicsLayerContextMenu.CallbackResults.CopyFrom(Me.MapInstance.CallbackResults) Case "Remove" If Me.MapInstance Is Nothing OrElse graphicsLayerNode Is Nothing Then Return End If ' Check whether there is a GraphicsLayer associated with the node If Not graphicsLayerNode.Layer Is Nothing Then ' Remove the GraphicsLayer associated with the node from the map and refresh the layer's ' parent resource Dim graphicsResourceName As String = graphicsLayerNode.RemoveFromMap(Me.TaskResultsInstance) Me.MapInstance.RefreshResource(graphicsResourceName) ' Copy the map's callback results to the context menu so the map is updated on the client _graphicsLayerContextMenu.CallbackResults.CopyFrom(Me.MapInstance.CallbackResults) End If ' Remove the node and refresh the buddied TaskResults control graphicsLayerNode.Remove() Me.TaskResultsInstance.Refresh() ' Copy the buddied TaskResults control's callback results to the context menu so the node removal ' is processed on the client _graphicsLayerContextMenu.CallbackResults.CopyFrom(TaskResultsInstance.CallbackResults) Case "View Attribute Table" ' Construct JavaScript to call the client-side Web ADF function to display the TaskResultsPanel Dim taskResultsPanelClientID As String = String.Format("{0}_{1}_TaskResultsPanel", Me.ClientID, args.Context) Dim showTaskResultsPanelJavaScript As String = String.Format("showFloatingPanel('{0}', false);", taskResultsPanelClientID) Dim showTaskResultsPanelCallbackResult As ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResult = ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResult.CreateJavaScript(showTaskResultsPanelJavaScript) _graphicsLayerContextMenu.CallbackResults.Add(showTaskResultsPanelCallbackResult) End Select End Sub #End Region #Region "Task Overrides - ExecuteTask" Public Overrides Sub ExecuteTask() ' Create a default set of results MyBase.ExecuteTask() ' Set a flag indicating that the task has executed as part of the current request Me._taskExecuted = True End Sub #End Region #Region "Instance Properties" ' Convenient access to the first TaskResults control in the Task's TaskResultsContainers collection Private ReadOnly Property TaskResultsInstance() As ESRI.ArcGIS.ADF.Web.UI.WebControls.TaskResults Get ' Retrieve the TaskResults control if it has not already been If (m_taskResults Is Nothing) AndAlso (Not TaskResultsContainers(0) Is Nothing) Then m_taskResults = TryCast(ESRI.ArcGIS.ADF.Web.UI.WebControls.Utility.FindControl(TaskResultsContainers(0).Name, Page), ESRI.ArcGIS.ADF.Web.UI.WebControls.TaskResults) End If Return m_taskResults End Get End Property ' Returns the buddied Map Private ReadOnly Property MapInstance() As ESRI.ArcGIS.ADF.Web.UI.WebControls.Map Get Return Me.TaskResultsInstance.MapInstance End Get End Property #End Region #Region "Instance Methods" ' Creates a TaskResultsPanel with the passed-in ID and title Private Function CreateTaskResultsPanel(ByVal ID As String, ByVal title As String) As ESRI.ADF.Samples.CustomTasks.TaskResultsPanel ' Initialize the TaskResultsPanel Dim taskResultsPanel As ESRI.ADF.Samples.CustomTasks.TaskResultsPanel = New ESRI.ADF.Samples.CustomTasks.TaskResultsPanel() taskResultsPanel.ID = ID taskResultsPanel.Visible = False taskResultsPanel.CopyAppearance(Me) taskResultsPanel.Style(System.Web.UI.HtmlTextWriterStyle.Position) = "absolute" taskResultsPanel.Style(System.Web.UI.HtmlTextWriterStyle.Left) = "200px" taskResultsPanel.Style(System.Web.UI.HtmlTextWriterStyle.Top) = "200px" taskResultsPanel.ExpandCollapseButton = True taskResultsPanel.WidthResizable = True taskResultsPanel.HeightResizable = True taskResultsPanel.Title = title taskResultsPanel.Docked = False taskResultsPanel.InitialMaxHeight = New System.Web.UI.WebControls.Unit(300, System.Web.UI.WebControls.UnitType.Pixel) taskResultsPanel.InitialMaxWidth = New System.Web.UI.WebControls.Unit(500, System.Web.UI.WebControls.UnitType.Pixel) ' Add the panel to the task's controls collection Me.Controls.Add(taskResultsPanel) ' Since we are adding the taskResultsPanel dynamically at run time, script must be created and ' returned to the client that initializes the panel client-side. InitializeOnClient creates ' this script and adds it to the panel as a callback result. taskResultsPanel.InitializeOnClient(Me, Me.CallbackFunctionString) Return taskResultsPanel End Function ' Instantiates and initializes the context menu to show on task results if results are being displayed in a ' TaskResultsPanel. Private Sub CreateTaskResultsPanelContextMenu() ' Instantiate and initialize the appearance of the context menu _graphicsLayerContextMenu = New ESRI.ArcGIS.ADF.Web.UI.WebControls.ContextMenu() _graphicsLayerContextMenu.ID = "graphicsLayerContextMenu" _graphicsLayerContextMenu.BorderColor = System.Drawing.Color.Silver _graphicsLayerContextMenu.BorderStyle = System.Web.UI.WebControls.BorderStyle.Solid _graphicsLayerContextMenu.BorderWidth = New System.Web.UI.WebControls.Unit(1, System.Web.UI.WebControls.UnitType.Pixel) _graphicsLayerContextMenu.HoverColor = System.Drawing.Color.Gainsboro _graphicsLayerContextMenu.BackColor = System.Drawing.Color.White _graphicsLayerContextMenu.ForeColor = ForeColor _graphicsLayerContextMenu.Font.CopyFrom(Me.Font) _graphicsLayerContextMenu.UseDefaultWebResources = Me.UseDefaultWebResources ' Wire item clicked and menu dismissed event handlers AddHandler _graphicsLayerContextMenu.ItemClicked, AddressOf GraphicsLayerContextMenu_ItemClicked AddHandler _graphicsLayerContextMenu.Dismissed, AddressOf GraphicsLayerContextMenu_Dismissed ' Add a menu item to zoom to selected features Dim contextMenuItem As ESRI.ArcGIS.ADF.Web.UI.WebControls.ContextMenuItem = New ESRI.ArcGIS.ADF.Web.UI.WebControls.ContextMenuItem() contextMenuItem.ImageUrl = "images/contextMenuZoomTo.gif" contextMenuItem.Text = "Zoom To Selected Features" _graphicsLayerContextMenu.Items.Add(contextMenuItem) ' Add a menu item to remove the GraphicsLayer corresponding to the node on which the context menu was shown contextMenuItem = New ESRI.ArcGIS.ADF.Web.UI.WebControls.ContextMenuItem() contextMenuItem.ImageUrl = "images/contextMenuRemove.gif" contextMenuItem.Text = "Remove" _graphicsLayerContextMenu.Items.Add(contextMenuItem) ' Add a menu item to show the corresponding TaskResultsPanel contextMenuItem = New ESRI.ArcGIS.ADF.Web.UI.WebControls.ContextMenuItem() contextMenuItem.ImageUrl = "images/contextMenuViewTable.gif" contextMenuItem.Text = "View Attribute Table" _graphicsLayerContextMenu.Items.Add(contextMenuItem) ' Add the context menu to the task's controls collection Me.Controls.Add(_graphicsLayerContextMenu) End Sub ' Retrieves a GraphicsLayerNode that is an ancestor or descendant of the passed-in node, if available Private Function GetRelatedGraphicsLayerNode(ByVal node As ESRI.ArcGIS.ADF.Web.UI.WebControls.TreeViewPlusNode) As ESRI.ArcGIS.ADF.Web.UI.WebControls.GraphicsLayerNode ' Check whether the passed-in node is a GraphicsLayerNode Dim graphicsLayerNode As ESRI.ArcGIS.ADF.Web.UI.WebControls.GraphicsLayerNode = TryCast(node, ESRI.ArcGIS.ADF.Web.UI.WebControls.GraphicsLayerNode) ' Check whether the passed-in node has an ancestor GraphicsLayerNode If graphicsLayerNode Is Nothing Then graphicsLayerNode = Me.FindParentGraphicsLayerNode(node) End If ' Check whether the passed-in node has a descendant GraphicsLayerNode If graphicsLayerNode Is Nothing Then graphicsLayerNode = Me.FindChildGraphicsLayerNode(node) End If Return graphicsLayerNode End Function ' Retrieves a GraphicsLayerNode that is a descendant of the passed-in node, if available Private Function FindChildGraphicsLayerNode(ByVal node As ESRI.ArcGIS.ADF.Web.UI.WebControls.TreeViewPlusNode) As ESRI.ArcGIS.ADF.Web.UI.WebControls.GraphicsLayerNode Dim graphicsLayerNode As ESRI.ArcGIS.ADF.Web.UI.WebControls.GraphicsLayerNode = TryCast(node, ESRI.ArcGIS.ADF.Web.UI.WebControls.GraphicsLayerNode) If graphicsLayerNode Is Nothing AndAlso node.Nodes.Count > 0 Then For Each childNode As ESRI.ArcGIS.ADF.Web.UI.WebControls.TreeViewPlusNode In node.Nodes graphicsLayerNode = Me.FindChildGraphicsLayerNode(childNode) If Not graphicsLayerNode Is Nothing Then Exit For End If Next childNode End If Return graphicsLayerNode End Function ' Retrieves a GraphicsLayerNode that is an ancestor of the passed-in node, if available Private Function FindParentGraphicsLayerNode(ByVal node As ESRI.ArcGIS.ADF.Web.UI.WebControls.TreeViewPlusNode) As ESRI.ArcGIS.ADF.Web.UI.WebControls.GraphicsLayerNode Dim graphicsLayerNode As ESRI.ArcGIS.ADF.Web.UI.WebControls.GraphicsLayerNode = TryCast(node, ESRI.ArcGIS.ADF.Web.UI.WebControls.GraphicsLayerNode) If graphicsLayerNode Is Nothing AndAlso TypeOf node.Parent Is ESRI.ArcGIS.ADF.Web.UI.WebControls.TreeViewPlusNode Then graphicsLayerNode = Me.FindParentGraphicsLayerNode(TryCast(node.Parent, ESRI.ArcGIS.ADF.Web.UI.WebControls.TreeViewPlusNode)) End If Return graphicsLayerNode End Function #End Region End Class End Namespace