Common_TaskResults_CSharp\TaskResultsWebSite\App_Code\TabularResultsTask.cs
// 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. // namespace ESRI.ADF.Samples.CustomTasks { public class TabularResultsTask : ESRI.ArcGIS.ADF.Tasks.QueryAttributesTask { #region Instance Variable Declarations // Stores a reference to the buddied TaskResults Control private ESRI.ArcGIS.ADF.Web.UI.WebControls.TaskResults m_taskResults = null; // Tracks whether the current page request has routed through ExecuteTask private bool _taskExecuted = false; // Stores a reference to the custom context menu that provides an option to view the // results table private ESRI.ArcGIS.ADF.Web.UI.WebControls.ContextMenu _graphicsLayerContextMenu; #endregion #region ASP.NET WebControl Life Cycle Event Handlers // Creates the custom task results context menu and wires task results control event handlers protected override void CreateChildControls() { base.CreateChildControls(); this.CreateTaskResultsPanelContextMenu(); // Add a handler to the buddied TaskResults Control's NodeAdded event this.TaskResultsInstance.NodeAdded += new ESRI.ArcGIS.ADF.Web.UI.WebControls.TreeViewPlusNodeAddedEventHandler(TaskResultsInstance_NodeAdded); this.TaskResultsInstance.NodeRemoved += new ESRI.ArcGIS.ADF.Web.UI.WebControls.TreeViewPlusNodeRemovedEventHandler(TaskResultsInstance_NodeRemoved); } // Registers the client script needed by TaskResultsPanel. We do this here since no // TaskResultsPanel is being created during application start-up. protected override void Render(System.Web.UI.HtmlTextWriter writer) { base.Render(writer); ESRI.ADF.Samples.CustomTasks.TaskResultsPanel.RegisterScripts(this); } #endregion #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. void TaskResultsInstance_NodeAdded(object sender, ESRI.ArcGIS.ADF.Web.UI.WebControls.TreeViewPlusNodeEventArgs args) { if (this._taskExecuted) { // Get the GraphicsLayerNode that is an ancestor or descendant of the current node ESRI.ArcGIS.ADF.Web.UI.WebControls.GraphicsLayerNode graphicsLayerNode = this.GetRelatedGraphicsLayerNode(args.Node); // Make sure a GraphicsLayerNode was found if (graphicsLayerNode != null) { // Create the TaskResultsPanel that will be used to display results string taskResultsPanelID = string.Format("{0}_TaskResultsPanel", graphicsLayerNode.NodeID); string taskResultsPanelTitle = string.Format("{0} - {1} {2}", this.Title, this.PredefinedQuery.FormEntries[0].LabelText, this.PredefinedQuery.FormEntries[0].UserInput); ESRI.ADF.Samples.CustomTasks.TaskResultsPanel taskResultsPanel = this.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. string checkDockJavaScript = string.Format("$find('{0}')._checkDock();", taskResultsPanel.ClientID); ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResult callbackResultToRemove = null; foreach (ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResult callbackResult in taskResultsPanel.CallbackResults) { if (callbackResult.Parameters[0] as string == checkDockJavaScript) { callbackResultToRemove = callbackResult; break; } } if (callbackResultToRemove != null) taskResultsPanel.CallbackResults.Remove(callbackResultToRemove); // Get the name of the resource containing the results GraphicsLayer string resourceName = 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. ESRI.ArcGIS.ADF.Web.Display.Graphics.FeatureGraphicsLayer featureGraphicsLayer = graphicsLayerNode.Layer as ESRI.ArcGIS.ADF.Web.Display.Graphics.FeatureGraphicsLayer; string graphicsLayerClientID = string.Format("{0}_{1} {2} Results_{3}", this.TaskResultsInstance.MapInstance.ClientID, this.TaskResultsInstance.ClientID, featureGraphicsLayer.FeatureType.ToString(), graphicsLayerNode.Layer.TableName); // Call SetLayer to associate the TaskResultsPanel with the GraphicsLayer taskResultsPanel.SetLayer(featureGraphicsLayer, resourceName, this.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 this.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 this.CallbackResults.CopyFrom(taskResultsPanel.CallbackResults); // Reset the flag indicating whether a new TaskResultsPanel needs to be created this._taskExecuted = false; } } } public override string GetCallbackResult() { return base.GetCallbackResult(); } // Checks whether the removed node is a GraphicsLayerNode and removes any associated TaskResultsPanel if so void TaskResultsInstance_NodeRemoved(object sender, ESRI.ArcGIS.ADF.Web.UI.WebControls.TreeViewPlusNodeRemovedEventArgs args) { // 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 ESRI.ArcGIS.ADF.Web.UI.WebControls.GraphicsLayerNode graphicsLayerNode = this.FindChildGraphicsLayerNode(args.Node); // Check whether a GraphicsLayerNode was found if (graphicsLayerNode != null) { // Construct JavaScript to find the TaskResultsPanel corresponding to the GraphicsLayerNode and // destroy it. string taskResultsPanelClientID = string.Format("{0}_{1}_TaskResultsPanel", this.ClientID, graphicsLayerNode.NodeID); string disposeResultsPanelJavaScript = @" var taskResultsPanel = $find('{0}'); if (taskResultsPanel) {{ taskResultsPanel.hide(false); taskResultsPanel.dispose(); }} var element = $get('{0}'); if (element) 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 ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResult disposeResultsPanelCallbackResult = ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResult.CreateJavaScript(disposeResultsPanelJavaScript); this.TaskResultsInstance.CallbackResults.Add(disposeResultsPanelCallbackResult); } } // Fires when the custom GraphicLayer context menu is closed. private void GraphicsLayerContextMenu_Dismissed(object sender, ESRI.ArcGIS.ADF.Web.UI.WebControls.ContextMenuDismissedEventArgs args) { this.TaskResultsInstance.ContextMenuDismissed(_graphicsLayerContextMenu, args); } // Fires when an item on the custom GraphicsLayer context menu is clicked private void GraphicsLayerContextMenu_ItemClicked(object sender, ESRI.ArcGIS.ADF.Web.UI.WebControls.ContextMenuItemEventArgs args) { // Get the node on which the context menu was displayed ESRI.ArcGIS.ADF.Web.UI.WebControls.GraphicsLayerNode graphicsLayerNode = TaskResultsInstance.Nodes.FindByNodeID(args.Context) as ESRI.ArcGIS.ADF.Web.UI.WebControls.GraphicsLayerNode; // Check the text of the item clicked switch (args.Item.Text) { case "Zoom To Selected Features": if (graphicsLayerNode == null || this.MapInstance == null) return; bool hasFeaturesSelected = false; // Get the GraphicsLayer associated with the node ESRI.ArcGIS.ADF.Web.Display.Graphics.GraphicsLayer graphicsLayer = graphicsLayerNode.Layer; // Declare an envelope to store the combined extent of all features in the layer ESRI.ArcGIS.ADF.Web.Geometry.Envelope adfEnvelope = 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 for (int i = 0; i < graphicsLayer.Rows.Count; i++) { if ((bool)graphicsLayer.Rows[i][graphicsLayer.IsSelectedColumn]) { hasFeaturesSelected = true; ESRI.ArcGIS.ADF.Web.Geometry.Geometry rowGeometry = graphicsLayer.GeometryFromRow(graphicsLayer.Rows[i]); adfEnvelope.Union(rowGeometry); } } if (!hasFeaturesSelected) return; // If combined envelope width or height is zero, zoom in the amount specified by the // ZoomToPointFactor property if (adfEnvelope.Width == 0 || adfEnvelope.Height == 0) { ESRI.ArcGIS.ADF.Web.Geometry.Point adfPoint = new ESRI.ArcGIS.ADF.Web.Geometry.Point(adfEnvelope.XMax, adfEnvelope.YMax); ESRI.ArcGIS.ADF.Web.Geometry.Envelope fullExtentEnvelope = this.MapInstance.GetFullExtent(); double widthMargin = (fullExtentEnvelope.Width / TaskResultsInstance.ZoomToPointFactor) / 2; double heightMargin = (fullExtentEnvelope.Height / TaskResultsInstance.ZoomToPointFactor) / 2; ESRI.ArcGIS.ADF.Web.Geometry.Envelope zoomToEnvelope = 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; this.MapInstance.Extent = zoomToEnvelope; } else { // Apply the combined feature extent to the map this.MapInstance.Extent = adfEnvelope; } // Copy the map's callback results to the context menu so the extent change is processed on the client _graphicsLayerContextMenu.CallbackResults.CopyFrom(this.MapInstance.CallbackResults); break; case "Remove": if (this.MapInstance == null || graphicsLayerNode == null) return; // Check whether there is a GraphicsLayer associated with the node if (graphicsLayerNode.Layer != null) { // Remove the GraphicsLayer associated with the node from the map and refresh the layer's // parent resource string graphicsResourceName = graphicsLayerNode.RemoveFromMap(this.TaskResultsInstance); this.MapInstance.RefreshResource(graphicsResourceName); // Copy the map's callback results to the context menu so the map is updated on the client _graphicsLayerContextMenu.CallbackResults.CopyFrom(this.MapInstance.CallbackResults); } // Remove the node and refresh the buddied TaskResults control graphicsLayerNode.Remove(); this.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); break; case "View Attribute Table": // Construct JavaScript to call the client-side Web ADF function to display the TaskResultsPanel string taskResultsPanelClientID = string.Format("{0}_{1}_TaskResultsPanel", this.ClientID, args.Context); string showTaskResultsPanelJavaScript = string.Format("showFloatingPanel('{0}', false);", taskResultsPanelClientID); ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResult showTaskResultsPanelCallbackResult = ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResult.CreateJavaScript(showTaskResultsPanelJavaScript); _graphicsLayerContextMenu.CallbackResults.Add(showTaskResultsPanelCallbackResult); break; } } #endregion #region Task Overrides - ExecuteTask public override void ExecuteTask() { // Create a default set of results base.ExecuteTask(); // Set a flag indicating that the task has executed as part of the current request this._taskExecuted = true; } #endregion #region Instance Properties // Convenient access to the first TaskResults control in the Task's TaskResultsContainers collection private ESRI.ArcGIS.ADF.Web.UI.WebControls.TaskResults TaskResultsInstance { get { // Retrieve the TaskResults control if it has not already been if ((m_taskResults == null) && (TaskResultsContainers[0] != null)) m_taskResults = ESRI.ArcGIS.ADF.Web.UI.WebControls.Utility.FindControl(TaskResultsContainers[0].Name, Page) as ESRI.ArcGIS.ADF.Web.UI.WebControls.TaskResults; return m_taskResults; } } // Returns the buddied Map private ESRI.ArcGIS.ADF.Web.UI.WebControls.Map MapInstance { get { return this.TaskResultsInstance.MapInstance; } } #endregion #region Instance Methods // Creates a TaskResultsPanel with the passed-in ID and title private ESRI.ADF.Samples.CustomTasks.TaskResultsPanel CreateTaskResultsPanel(string ID, string title) { // Initialize the TaskResultsPanel ESRI.ADF.Samples.CustomTasks.TaskResultsPanel taskResultsPanel = new ESRI.ADF.Samples.CustomTasks.TaskResultsPanel(); taskResultsPanel.ID = ID; taskResultsPanel.Visible = false; taskResultsPanel.CopyAppearance(this); 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 this.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(this, this.CallbackFunctionString); return taskResultsPanel; } // Instantiates and initializes the context menu to show on task results if results are being displayed in a // TaskResultsPanel. private void 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(this.Font); _graphicsLayerContextMenu.UseDefaultWebResources = this.UseDefaultWebResources; // Wire item clicked and menu dismissed event handlers _graphicsLayerContextMenu.ItemClicked += new ESRI.ArcGIS.ADF.Web.UI.WebControls.ContextMenuItemClickedEventHandler( this.GraphicsLayerContextMenu_ItemClicked); _graphicsLayerContextMenu.Dismissed += new ESRI.ArcGIS.ADF.Web.UI.WebControls.ContextMenuDismissedEventHandler( this.GraphicsLayerContextMenu_Dismissed); // Add a menu item to zoom to selected features ESRI.ArcGIS.ADF.Web.UI.WebControls.ContextMenuItem 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 this.Controls.Add(_graphicsLayerContextMenu); } // Retrieves a GraphicsLayerNode that is an ancestor or descendant of the passed-in node, if available private ESRI.ArcGIS.ADF.Web.UI.WebControls.GraphicsLayerNode GetRelatedGraphicsLayerNode( ESRI.ArcGIS.ADF.Web.UI.WebControls.TreeViewPlusNode node) { // Check whether the passed-in node is a GraphicsLayerNode ESRI.ArcGIS.ADF.Web.UI.WebControls.GraphicsLayerNode graphicsLayerNode = node as ESRI.ArcGIS.ADF.Web.UI.WebControls.GraphicsLayerNode; // Check whether the passed-in node has an ancestor GraphicsLayerNode if (graphicsLayerNode == null) graphicsLayerNode = this.FindParentGraphicsLayerNode(node); // Check whether the passed-in node has a descendant GraphicsLayerNode if (graphicsLayerNode == null) graphicsLayerNode = this.FindChildGraphicsLayerNode(node); return graphicsLayerNode; } // Retrieves a GraphicsLayerNode that is a descendant of the passed-in node, if available private ESRI.ArcGIS.ADF.Web.UI.WebControls.GraphicsLayerNode FindChildGraphicsLayerNode( ESRI.ArcGIS.ADF.Web.UI.WebControls.TreeViewPlusNode node) { ESRI.ArcGIS.ADF.Web.UI.WebControls.GraphicsLayerNode graphicsLayerNode = node as ESRI.ArcGIS.ADF.Web.UI.WebControls.GraphicsLayerNode; if (graphicsLayerNode == null && node.Nodes.Count > 0) { foreach (ESRI.ArcGIS.ADF.Web.UI.WebControls.TreeViewPlusNode childNode in node.Nodes) { graphicsLayerNode = this.FindChildGraphicsLayerNode(childNode); if (graphicsLayerNode != null) break; } } return graphicsLayerNode; } // Retrieves a GraphicsLayerNode that is an ancestor of the passed-in node, if available private ESRI.ArcGIS.ADF.Web.UI.WebControls.GraphicsLayerNode FindParentGraphicsLayerNode( ESRI.ArcGIS.ADF.Web.UI.WebControls.TreeViewPlusNode node) { ESRI.ArcGIS.ADF.Web.UI.WebControls.GraphicsLayerNode graphicsLayerNode = node as ESRI.ArcGIS.ADF.Web.UI.WebControls.GraphicsLayerNode; if (graphicsLayerNode == null && node.Parent is ESRI.ArcGIS.ADF.Web.UI.WebControls.TreeViewPlusNode) graphicsLayerNode = this.FindParentGraphicsLayerNode(node.Parent as ESRI.ArcGIS.ADF.Web.UI.WebControls.TreeViewPlusNode); return graphicsLayerNode; } #endregion } }