Common_MapTips_CSharp\App_Code\AttributesOnDemandTask.cs
// 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. // namespace ESRI.ADF.Samples.CustomTasks { public class AttributesOnDemandTask : 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; #endregion #region ASP.NET WebControl Life Cycle Event Handlers protected override void CreateChildControls() { base.CreateChildControls(); // Add a handler to the buddied TaskResults Control's NodeAdded event this.TaskResultsInstance.NodeAdded += new ESRI.ArcGIS.ADF.Web.UI.WebControls.TreeViewPlusNodeAddedEventHandler(TaskResultsInstance_NodeAdded); } #endregion #region Web ADF Control Event Handlers // Retrieves the results graphics layer and enables Attribute-on-demand MapTips. Needs to be 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) { // Check whether the currently added node has a parent or child graphics layer and the task has executed during the // current request ESRI.ArcGIS.ADF.Web.UI.WebControls.GraphicsLayerNode graphicsLayerNode = this.GetRelatedGraphicsLayerNode(args.Node); if (graphicsLayerNode != null && this._taskExecuted) { // Retrieve the task's layerFormat ESRI.ArcGIS.ADF.Web.UI.WebControls.LayerFormat layerFormat = ESRI.ArcGIS.ADF.Web.UI.WebControls.LayerFormat.FromMapResourceManager( this.TaskResultsInstance.MapInstance.MapResourceManagerInstance, this.PredefinedQuery.MapResource, this.PredefinedQuery.LayerID); // Iterate through the fields of the LayerFormat and create the HTML markup for the MapTips content area that // will be used after attribute data has been retrieved string uniqueIDField = null; string currentTemplateRow = null; System.Collections.Generic.List<string> defaultTemplateRows = new System.Collections.Generic.List<string>(); string hasAttributesTemplate = "<table>"; foreach (ESRI.ArcGIS.ADF.Web.DataSources.FieldInfo fieldInfo in layerFormat.Fields) { if (fieldInfo.Visible) { currentTemplateRow = "<tr><td style='font-weight:bold; border-bottom: solid 1px gray; " + "border-right: solid 1px gray;'>{0}</td>" + "<td style='border-bottom: solid 1px gray; border-right: solid 1px gray;'>{{{{@{1}}}}}</td></tr>"; currentTemplateRow = string.Format(currentTemplateRow, fieldInfo.Alias, fieldInfo.Name); defaultTemplateRows.Add(currentTemplateRow); } // If the current field is a unique identifier, store a reference to the field name if (graphicsLayerNode.Layer.Columns[fieldInfo.Name].Unique) uniqueIDField = fieldInfo.Name; } foreach (string templateRow in defaultTemplateRows) hasAttributesTemplate += templateRow; hasAttributesTemplate += "</table>"; // Get the URL of the Web ADF activity indicator string activityIndicatorUrl = ESRI.ArcGIS.ADF.Web.UI.WebControls.ResourceUtility.GetImage( "callbackActivityIndicator.gif", this, typeof(ESRI.ArcGIS.ADF.Web.UI.WebControls.FloatingPanelTask), "Runtime"); // Create the HTML markup for the MapTips content area while attribute data is being retrieved string retrievingAttributesTemplate = "<div style='white-space:nowrap; font-family:Arial; " + "font-style:italic; font-size:10pt; color:gray;'><img src='{0}' />Retrieving Attribute Data</div>"; retrievingAttributesTemplate = string.Format(retrievingAttributesTemplate, activityIndicatorUrl); // Get a reference to the node's graphics layer as a FeatureGraphicsLayer ESRI.ArcGIS.ADF.Web.Display.Graphics.FeatureGraphicsLayer featureGraphicsLayer = graphicsLayerNode.Layer as ESRI.ArcGIS.ADF.Web.Display.Graphics.FeatureGraphicsLayer; // 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. string graphicsLayerID = string.Format("{0}_{1} {2} Results_{3}", this.TaskResultsInstance.MapInstance.ClientID, this.TaskResultsInstance.ClientID, featureGraphicsLayer.FeatureType.ToString(), graphicsLayerNode.Layer.TableName); string id = this.TaskResultsInstance.MapInstance.GetGraphicsLayerClientID(featureGraphicsLayer); // JavaScript to call the attributes-on-demand MapTips initialization method. Here the content templates are // explicitly defined. If they are not, default templates will be used. string enableAttributesOnDemandJavaScript = @" window.setTimeout(""var graphicFeatureGroup = $find('{0}');"" + ""var retrievingAttributesTemplate = String.format(\""{1}\"", graphicFeatureGroup.get_id());"" + ""var hasAttributesTemplate = String.format(\""{2}\"", graphicFeatureGroup.get_id());"" + ""graphicFeatureGroup.setupMapTipsAttributesOnDemand(retrievingAttributesTemplate, hasAttributesTemplate,"" + ""'{3}', '{4}', '{5}', \""{6}\"");"", 0);"; enableAttributesOnDemandJavaScript = string.Format(enableAttributesOnDemandJavaScript, graphicsLayerID, retrievingAttributesTemplate, hasAttributesTemplate, uniqueIDField, this.PredefinedQuery.LayerID, this.PredefinedQuery.MapResource, this.CallbackFunctionString); ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResult enableAttributesOnDemandCallbackResult = ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResult.CreateJavaScript(enableAttributesOnDemandJavaScript); this.CallbackResults.Add(enableAttributesOnDemandCallbackResult); } } #endregion #region Task Overrides public override void ExecuteTask() { // Create a default set of results base.ExecuteTask(); this._taskExecuted = true; } public override string GetCallbackResult() { System.Collections.Specialized.NameValueCollection callbackArgs = ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackUtility.ParseStringIntoNameValueCollection(this.CallbackEventArgument); // Check whether the callback event argument indicates retrieval of MapTips attributes if (callbackArgs["EventArg"] == "retrieveMapTipsAttributes") { // === USED ONLY FOR DEMONSTRATION - REMOVE FOR PRODUCTION PURPOSES == // Suspend the current thread to allow the retrieving attributes indicator to display System.Threading.Thread.Sleep(1000); base.GetCallbackResult(); // Get a reference to the resource that was passed as part of the callback arguments ESRI.ArcGIS.ADF.Web.DataSources.IMapFunctionality commonMapFunctionality = this.TaskResultsInstance.MapInstance.GetFunctionality(callbackArgs["ResourceName"]); ESRI.ArcGIS.ADF.Web.DataSources.IGISResource gisResource = commonMapFunctionality.Resource; // Retrieve query functionality for the resource ESRI.ArcGIS.ADF.Web.DataSources.IQueryFunctionality commonQueryFunctionality = (ESRI.ArcGIS.ADF.Web.DataSources.IQueryFunctionality) gisResource.CreateFunctionality( typeof(ESRI.ArcGIS.ADF.Web.DataSources.IQueryFunctionality), null); // Initialize a query filter ESRI.ArcGIS.ADF.Web.QueryFilter adfQueryFilter = new ESRI.ArcGIS.ADF.Web.QueryFilter(); adfQueryFilter.ReturnADFGeometries = false; // Create the query clause with information passed from the maptips in the callback adfQueryFilter.WhereClause = string.Format("{0} = {1}", callbackArgs["UniqueIDField"], callbackArgs["FeatureID"]); // Execute the query System.Data.DataTable resultsTable = commonQueryFunctionality.Query(null, callbackArgs["LayerID"], adfQueryFilter); if (resultsTable == null) return base.GetCallbackResult(); // Create a JSON string with the results feature's attributes string jsonAttributes = "{ "; foreach (System.Data.DataColumn column in resultsTable.Columns) jsonAttributes += string.Format("'{0}':'{1}', ", column.ColumnName, resultsTable.Rows[0][column.ColumnName]); jsonAttributes = string.Format("{0} }}", jsonAttributes.Substring(0, jsonAttributes.Length - 2)); // JavaScript needed to apply the queried feature's attributes to the mapTips string updateAttributesJavaScript = string.Format("$find('{0}').get_mapTips().updateAttributes({1}, '{2}');", callbackArgs["GraphicFeatureGroupID"], jsonAttributes, callbackArgs["FeatureID"]); ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResult updateAttributesCallbackResult = ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResult.CreateJavaScript(updateAttributesJavaScript); this.CallbackResults.Add(updateAttributesCallbackResult); return this.CallbackResults.ToString(); } else { return base.GetCallbackResult(); } } #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; } } #endregion #region Instance Methods // 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 } }