Common_ExtendTasks_CSharp\App_Code\ExtendQueryTask.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 ExtendedTasks { public class ExtendQueryTask : ESRI.ArcGIS.ADF.Tasks.QueryAttributesTask { #region Instance Variable Declarations ESRI.ArcGIS.ADF.Web.UI.WebControls.ContextMenu m_customContextMenuSimpleResult; ESRI.ArcGIS.ADF.Web.UI.WebControls.TaskResults m_taskResults = null; #endregion #region ASP.NET WebControl Life Cycle Event Overrids // Add custom context menu to the task's controls collection protected override void CreateChildControls() { // Create the default task controls base.CreateChildControls(); // Instantiate context menu and configure appearance m_customContextMenuSimpleResult = new ESRI.ArcGIS.ADF.Web.UI.WebControls.ContextMenu(); m_customContextMenuSimpleResult.ID = "customContextMenu"; m_customContextMenuSimpleResult.BorderColor = System.Drawing.Color.Silver; m_customContextMenuSimpleResult.BorderStyle = System.Web.UI.WebControls.BorderStyle.Solid; m_customContextMenuSimpleResult.BorderWidth = new System.Web.UI.WebControls.Unit(1, System.Web.UI.WebControls.UnitType.Pixel); m_customContextMenuSimpleResult.HoverColor = System.Drawing.Color.Gainsboro; m_customContextMenuSimpleResult.BackColor = System.Drawing.Color.White; m_customContextMenuSimpleResult.ForeColor = System.Drawing.Color.Black; m_customContextMenuSimpleResult.UseDefaultWebResources = true; m_customContextMenuSimpleResult.Font.Name = "Verdana"; m_customContextMenuSimpleResult.Font.Size = new System.Web.UI.WebControls.FontUnit(8); // Add handlers to fire when an item is clicked and when the menu is dismissed m_customContextMenuSimpleResult.ItemClicked += new ESRI.ArcGIS.ADF.Web.UI.WebControls.ContextMenuItemClickedEventHandler( customContextMenuSimpleResult_ItemClicked); m_customContextMenuSimpleResult.Dismissed += new ESRI.ArcGIS.ADF.Web.UI.WebControls.ContextMenuDismissedEventHandler( customContextMenuSimpleResult_Dismissed); // Add a menu item with the text "Show Alert" ESRI.ArcGIS.ADF.Web.UI.WebControls.ContextMenuItem showAlertContextMenuItem = new ESRI.ArcGIS.ADF.Web.UI.WebControls.ContextMenuItem(); showAlertContextMenuItem.Text = "Show Alert"; showAlertContextMenuItem.ImageUrl = ""; m_customContextMenuSimpleResult.Items.Add(showAlertContextMenuItem); // Add a menu item with the text "Zoom To Feature" and a picture of a wrench ESRI.ArcGIS.ADF.Web.UI.WebControls.ContextMenuItem zoomToFeatureContextMenuItem = new ESRI.ArcGIS.ADF.Web.UI.WebControls.ContextMenuItem(); zoomToFeatureContextMenuItem.Text = "Zoom To Feature"; zoomToFeatureContextMenuItem.ImageUrl = "images/wrench.gif"; m_customContextMenuSimpleResult.Items.Add(zoomToFeatureContextMenuItem); // Add the context menu to the task's controls collection Controls.Add(m_customContextMenuSimpleResult); } protected override void OnLoad(System.EventArgs eventArgs) { base.OnLoad(eventArgs); // Add an event handler that fires when a node on the associated task results container is clicked this.TaskResultsInstance.NodeClicked += new ESRI.ArcGIS.ADF.Web.UI.WebControls.TreeViewPlusNodeClickedEventHandler(TaskResults_NodeClicked); // Add an item to the custom context menu to remove nodes. To do this, we simply use the item from the // associated task results container's RemoveOnly context menu m_customContextMenuSimpleResult.Items.Add(TaskResultsInstance.RemoveOnlyContextMenu.Items[0]); } #endregion #region Web ADF WebControl Event Handlers void TaskResults_NodeClicked(object sender, ESRI.ArcGIS.ADF.Web.UI.WebControls.TreeViewPlusNodeEventArgs treeViewPlusNodeEventArgs) { // Get the text of the node that was clicked string nodeText = treeViewPlusNodeEventArgs.Node.Text; // Construct a JavaScript callback result that will update the window's status bar with the text of the // clicked node and the current millisecond of the server's DateTime object string jsUpdateStatusBar = string.Format("window.status = 'Clicked on {0} during millisecond value of {1}'", nodeText, System.DateTime.Now.Millisecond); ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResult updateStatusBarCallbackResult = ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResult.CreateJavaScript(jsUpdateStatusBar); TaskResultsInstance.CallbackResults.Add(updateStatusBarCallbackResult); } void customContextMenuSimpleResult_Dismissed(object sender, ESRI.ArcGIS.ADF.Web.UI.WebControls.ContextMenuDismissedEventArgs contextMenuDismissedEventArgs) { // Get the task results node that was clicked to display the context menu ESRI.ArcGIS.ADF.Web.UI.WebControls.TreeViewPlusNode treeViewPlusNode = TaskResultsInstance.Nodes.FindByNodeID(contextMenuDismissedEventArgs.Context); if (treeViewPlusNode != null) { // Construct a JavaScript callback to unselect the node in the TaskResults container string jsUnselectResultsNode = string.Format("var node = document.getElementById('{0}_textCell');" + "if(node!=null){{node.style.backgroundColor='{1}';}}", treeViewPlusNode.NodeID, System.Drawing.ColorTranslator.ToHtml(TaskResultsInstance.BackColor)); ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResult unselectResultsNodeCallbackResult = ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResult.CreateJavaScript(jsUnselectResultsNode); m_customContextMenuSimpleResult.CallbackResults.Add(unselectResultsNodeCallbackResult); } } void customContextMenuSimpleResult_ItemClicked(object sender, ESRI.ArcGIS.ADF.Web.UI.WebControls.ContextMenuItemEventArgs contextMenuItemEventArgs) { // Get the task results node that was right-clicked to display the context menu ESRI.ArcGIS.ADF.Web.UI.WebControls.TreeViewPlusNode treeViewPlusNode = TaskResultsInstance.Nodes.FindByNodeID(contextMenuItemEventArgs.Context); // Determine which context menu item was clicked by checking the text of the passed-in item switch (contextMenuItemEventArgs.Item.Text) { case "Show Alert": // Construct a JavaScript callback to display an alert showing the worker process identity // under which the application is running string jsWorkerProcessIdentityAlert = string.Format("alert('Worker process identity: {0}')", System.Security.Principal.WindowsIdentity.GetCurrent().Name.Replace("\\", "\\\\")); ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResult workerProcessIdentityAlertCallbackResult = ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResult.CreateJavaScript(jsWorkerProcessIdentityAlert); m_customContextMenuSimpleResult.CallbackResults.Add(workerProcessIdentityAlertCallbackResult); break; case "Zoom To Feature": // Make sure the node on which the context menu was shown is a FeatureNode (i.e. corresponds to a // feature on the map) if (treeViewPlusNode is ESRI.ArcGIS.ADF.Web.UI.WebControls.FeatureNode) { // Get a reference to the node as a FeatureNode ESRI.ArcGIS.ADF.Web.UI.WebControls.FeatureNode featureNode = (ESRI.ArcGIS.ADF.Web.UI.WebControls.FeatureNode)treeViewPlusNode; // Get the feature's data as a row System.Data.DataRow dataRow = featureNode.DataRow; // Get the graphics layer containing the feature ESRI.ArcGIS.ADF.Web.Display.Graphics.FeatureGraphicsLayer featureGraphicsLayer = (ESRI.ArcGIS.ADF.Web.Display.Graphics.FeatureGraphicsLayer)dataRow.Table; // Get the feature's geometry ESRI.ArcGIS.ADF.Web.Geometry.Geometry adfGeometry = featureGraphicsLayer.GeometryFromRow(dataRow); // Get the bounding envelope of the geometry ESRI.ArcGIS.ADF.Web.Geometry.Envelope boundingEnvelope = new ESRI.ArcGIS.ADF.Web.Geometry.Envelope(double.MaxValue, double.MaxValue, double.MinValue, double.MinValue); if (adfGeometry is ESRI.ArcGIS.ADF.Web.Geometry.Polygon) { GetBoundingExtent((ESRI.ArcGIS.ADF.Web.Geometry.Polygon)adfGeometry, boundingEnvelope); // Expand the envelope to include some area on the map around the feature boundingEnvelope = boundingEnvelope.Expand(10); } else if (adfGeometry is ESRI.ArcGIS.ADF.Web.Geometry.Point) { GetBoundingExtent((ESRI.ArcGIS.ADF.Web.Geometry.Point)adfGeometry, boundingEnvelope); // Expand the bounding envelope so that it is 1/8 of the map width. We do this instead of using // Envelope.Expand because that method expands by percentage. Since the bounding envelope of a // poing geometry has a height and width of zero, expanding by any percentage will result in no // change. double mapWidthSixteenth = TaskResultsInstance.MapInstance.GetFullExtent().Width / 16; boundingEnvelope = new ESRI.ArcGIS.ADF.Web.Geometry.Envelope( boundingEnvelope.XMin - mapWidthSixteenth, boundingEnvelope.YMin - mapWidthSixteenth, boundingEnvelope.XMax + mapWidthSixteenth, boundingEnvelope.YMax + mapWidthSixteenth); } // Set the map's extent to be the bounding envelope TaskResultsInstance.MapInstance.Extent = boundingEnvelope; // Copy the map's callback results (created by changing the extent) to the custom context menu so // that they are processed on the client m_customContextMenuSimpleResult.CallbackResults.CopyFrom( TaskResultsInstance.MapInstance.CallbackResults); } break; case "Remove": // Remove the node, refresh the task results control, and return callback results accordingly treeViewPlusNode.Parent.Nodes.Remove(treeViewPlusNode); TaskResultsInstance.Refresh(); m_customContextMenuSimpleResult.CallbackResults.CopyFrom(TaskResultsInstance.CallbackResults); break; } } #endregion #region QueryAttributesTask Overrides // Customizes the task results public override void ExecuteTask() { // Call the base task's ExcecuteTask function so that a default set of results is created base.ExecuteTask(); // Only manipulate the results if they are returned in a DataSet. If they are not, that means no results // were found or there was an error. if (Results is System.Data.DataSet) { System.Data.DataSet resultsDataSet = Results as System.Data.DataSet; // Get the callback arguments from CallbackEventArgument, which contains callback arg/val pairs System.Collections.Specialized.NameValueCollection callbackArgumentsCollection = ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackUtility.ParseStringIntoNameValueCollection( this.CallbackEventArgument); // Remove any results already generated by this task foreach (ESRI.ArcGIS.ADF.Web.UI.WebControls.TreeViewPlusNode treeViewPlusNode in TaskResultsInstance.Nodes) { if (treeViewPlusNode.Text.StartsWith("Selected Set")) { RemoveResultsFromMap(treeViewPlusNode as ESRI.ArcGIS.ADF.Web.UI.WebControls.TaskResultNode); treeViewPlusNode.Remove(); TaskResultsInstance.Refresh(); break; } } // Retrieve the task's job ID from the callback arguments string taskJobID = callbackArgumentsCollection["taskJobID"]; // Create a new task results node to display the non-spatial results data ESRI.ArcGIS.ADF.Web.UI.WebControls.TaskResultNode taskResultsNode = new ESRI.ArcGIS.ADF.Web.UI.WebControls.TaskResultNode("Selected Set"); // Associate the node with the Task Results container TaskResultsInstance.SetupTaskResultNode(this, taskJobID, Input, taskResultsNode); // Make sure the results dataset contains tables if (resultsDataSet.Tables != null) { // If the properties of the task results container specifies that the number of feature found // (i.e. rows) is to be shown, append the number of rows to the text of the task results node if (TaskResultsInstance.ShowRowCount) { int rowCount = 0; for (int i = 0; i < resultsDataSet.Tables.Count; i++) rowCount += resultsDataSet.Tables[i].Rows.Count; taskResultsNode.Text += System.String.Format(" ({0})", rowCount); } System.Data.DataTable resultsDataTable = null; ESRI.ArcGIS.ADF.Web.UI.WebControls.TreeViewPlusNode dataTableTreeViewPlusNode = null; // Loop through the tables in the results dataSet, adding the data for each to the results node for (int i = 0; i < resultsDataSet.Tables.Count; i++) { resultsDataTable = resultsDataSet.Tables[i]; // Check whether the current table can be cast to a Web ADF GraphicsLayer if (resultsDataTable is ESRI.ArcGIS.ADF.Web.Display.Graphics.GraphicsLayer) { // Since the current data table is a GraphicsLayer, create a GraphicsLayerNode for it. This // will enable functionality such as zooming to the layer and toggling the entire layer's // visiblity when the node is checked/unchecked ESRI.ArcGIS.ADF.Web.Display.Graphics.GraphicsLayer adfGraphicsLayer = resultsDataTable as ESRI.ArcGIS.ADF.Web.Display.Graphics.GraphicsLayer; dataTableTreeViewPlusNode = new ESRI.ArcGIS.ADF.Web.UI.WebControls.GraphicsLayerNode( adfGraphicsLayer, this.ShowLegend, null, null); // If the number of features in the layer are to be shown, append this number to the text of // the node if (TaskResultsInstance.ShowRowCount) dataTableTreeViewPlusNode.Text += System.String.Format(" ({0})", adfGraphicsLayer.Rows.Count); TaskResultsInstance.SetupContextMenu(TaskResultsInstance.GraphicsLayerContextMenu, dataTableTreeViewPlusNode); } else { // Since the dataTable is not a graphics layer, set up a node without spatial functionality dataTableTreeViewPlusNode = new ESRI.ArcGIS.ADF.Web.UI.WebControls.TreeViewPlusNode(resultsDataTable.TableName); dataTableTreeViewPlusNode.ShowCheckBox = false; TaskResultsInstance.SetupContextMenu(TaskResultsInstance.RemoveOnlyContextMenu, dataTableTreeViewPlusNode); } // Set the data table node to expand or collapse when clicked dataTableTreeViewPlusNode.ClickBehavior = ESRI.ArcGIS.ADF.Web.UI.WebControls.TreeViewPlusNodeClickBehavior.ExpandCollapse; // If the task results control's properties specifies showing a legend for results, add a text-only // node with the text "Features" to the results node tree before adding feature nodes if (this.ShowLegend && resultsDataTable is ESRI.ArcGIS.ADF.Web.Display.Graphics.GraphicsLayer) { ESRI.ArcGIS.ADF.Web.UI.WebControls.TreeViewPlusNode featuresNode = new ESRI.ArcGIS.ADF.Web.UI.WebControls.TreeViewPlusNode("Features"); featuresNode.ShowCheckBox = false; featuresNode.ClickBehavior = ESRI.ArcGIS.ADF.Web.UI.WebControls.TreeViewPlusNodeClickBehavior.None; dataTableTreeViewPlusNode.Nodes.Add(featuresNode); } // Get the display field from the result table's extended properties string displayFieldName = resultsDataTable.ExtendedProperties[ ESRI.ArcGIS.ADF.Web.Constants.ADFHeader] as string; System.Data.DataRow dataRow = null; ESRI.ArcGIS.ADF.Web.UI.WebControls.TreeViewPlusNode featureNode = null; ESRI.ArcGIS.ADF.Web.UI.WebControls.TreeViewPlusNode attributesNode = null; // Get a default template to use in displaying the non-spatial results string contentsTemplate = ESRI.ArcGIS.ADF.Web.Display.Graphics.GraphicsLayer.GetContentsTemplate( resultsDataTable, false, TaskResultsInstance.SelectedColor, true); // Loop through the individual results (rows/features), creating a node for each for (int j = 0; j < resultsDataTable.Rows.Count; j++) { dataRow = resultsDataTable.Rows[j]; // Create a hyperlink for state name values. To do this, get the value of the STATE_NAME field // for the current row, add hyperlink markup around it, and re-assign the STATE_NAME value with // the marked-up text string stateName = dataRow["STATE_NAME"] as string; string hyperlinkedStateName = "<a target='_blank' href='http://www.google.com/search?q=" + stateName + "' >" + stateName + "</a>"; dataRow["STATE_NAME"] = hyperlinkedStateName; // If the results are a feature graphics layer, create a node with highlighting and zoom-to // functionality. if (resultsDataTable is ESRI.ArcGIS.ADF.Web.Display.Graphics.FeatureGraphicsLayer) { ESRI.ArcGIS.ADF.Web.Display.Graphics.FeatureGraphicsLayer featureGraphicsLayer = resultsDataTable as ESRI.ArcGIS.ADF.Web.Display.Graphics.FeatureGraphicsLayer; // Create a feature node based on the data row and the value in the display field string displayValue = dataRow[displayFieldName] as string; featureNode = new ESRI.ArcGIS.ADF.Web.UI.WebControls.FeatureNode(displayValue, dataRow); // Get a reference to the current node as a GraphicsLayerNode ESRI.ArcGIS.ADF.Web.UI.WebControls.GraphicsLayerNode graphicsLayerNode = dataTableTreeViewPlusNode as ESRI.ArcGIS.ADF.Web.UI.WebControls.GraphicsLayerNode; // Retrieve the client-side ID of the graphics layer. Note that GetGraphicsLayerClientID // isn't implemented for task results graphics layers, so we have to manually assemble the // ID from the map ID, resource name of the task results, and results data table name. //string graphicsLayerID = // this.TaskResultsInstance.MapInstance.GetGraphicsLayerClientID(featureGraphicsLayer); string graphicsLayerID = string.Format("{0}_{1}_{2}", TaskResultsInstance.MapInstance.ClientID, graphicsLayerNode.GetResourceName(TaskResultsInstance), resultsDataTable.TableName); // Create a JavaScript string that will (1) set the text color of the current node // (2) get the graphicFeatureGroup (i.e. layer) for the GraphicsLayer, (3) get the // graphicFeature corresponding to the current row index from the graphicFeatureGroup, // and (4) set the highlight on the graphicFeature //string jsSetRowAndFeatureHighlight = "for (var obj in Sys.Application._components)" + // "{ alert(obj); }" + // "while (obj != null);"; string jsSetRowAndFeatureHighlight = "this.style.color='{0}';" + "var graphicFeatureGroup = $find('{1}');" + "var graphicFeature = graphicFeatureGroup.get({2});" + "graphicFeature.set_highlight({3});"; // Assign the JavaScript to the node's onmouseover and onmouseout events. Highlight // the graphics and change the node text's color on mouseover, then un-highlight and // reset the node text's color on mouseout. Note that the iterator j is used for the // graphicFeature's index, since this coincides with the index of the current dataRow // in the results table featureNode.Attributes.Add("onmouseover", string.Format(jsSetRowAndFeatureHighlight, System.Drawing.ColorTranslator.ToHtml(TaskResultsInstance.HoverColor), graphicsLayerID, j, "true")); featureNode.Attributes.Add("onmouseout", string.Format(jsSetRowAndFeatureHighlight, System.Drawing.ColorTranslator.ToHtml(TaskResultsInstance.ForeColor), graphicsLayerID, j, "false")); // Specify left and right-click behavior featureNode.ClickBehavior = ESRI.ArcGIS.ADF.Web.UI.WebControls.TreeViewPlusNodeClickBehavior.ExpandCollapse; TaskResultsInstance.SetupContextMenu(m_customContextMenuSimpleResult, featureNode); } else { // Set-up a node that simply shows the text of the display field featureNode = new ESRI.ArcGIS.ADF.Web.UI.WebControls.TreeViewPlusNode( dataRow[displayFieldName] as string); featureNode.ClickBehavior = ESRI.ArcGIS.ADF.Web.UI.WebControls.TreeViewPlusNodeClickBehavior.None; featureNode.ShowCheckBox = false; featureNode.ClickBehavior = ESRI.ArcGIS.ADF.Web.UI.WebControls.TreeViewPlusNodeClickBehavior.ExpandCollapse; TaskResultsInstance.SetupContextMenu(TaskResultsInstance.RemoveOnlyContextMenu, featureNode); } // Add the feature node to the data table (i.e. graphics layer) node dataTableTreeViewPlusNode.Nodes.Add(featureNode); // Create a node to display the attributes of the current row (i.e. feature) attributesNode = new ESRI.ArcGIS.ADF.Web.UI.WebControls.TreeViewPlusNode(); // Use the graphics layer's contents template to initialize the attribute node's text. // This formats the contents of the dataRow into html mark-up based on the specifications // of the template. attributesNode.Text = string.Format(contentsTemplate, dataRow.ItemArray); attributesNode.ShowCheckBox = false; attributesNode.ClickBehavior = ESRI.ArcGIS.ADF.Web.UI.WebControls.TreeViewPlusNodeClickBehavior.None; featureNode.Nodes.Add(attributesNode); } contentsTemplate = null; // Add the data table (i.e. graphics layer) node to the root results node taskResultsNode.Nodes.Add(dataTableTreeViewPlusNode); if (!this.GroupResultsByTable) dataTableTreeViewPlusNode.HideNodeShowChildren = true; } } Results = taskResultsNode; } } #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 = Utility.FindControl(TaskResultsContainers[0].Name, Page) as ESRI.ArcGIS.ADF.Web.UI.WebControls.TaskResults; return m_taskResults; } } #endregion #region Instance Methods private void RemoveResultsFromMap(ESRI.ArcGIS.ADF.Web.UI.WebControls.TaskResultNode taskResultNode) { // Make sure the task results control is associated with a map control if (TaskResultsInstance.MapInstance == null) return; // Remove the task result graphics from the map and get a list of resources affected by this System.Collections.Generic.List<string> resourcesToRefresh = new System.Collections.Generic.List<string>(); RemoveResultGraphics(taskResultNode, ref resourcesToRefresh); // Refresh the resources affected by graphics removal so the changes are shown on the map foreach (string resourceName in resourcesToRefresh) TaskResultsInstance.MapInstance.RefreshResource(resourceName); CallbackResults.CopyFrom(TaskResultsInstance.MapInstance.CallbackResults); } private void RemoveResultGraphics(ESRI.ArcGIS.ADF.Web.UI.WebControls.TreeViewPlusNode treeViewPlusNode, ref System.Collections.Generic.List<string> affectedResourceList) { string affectedResourceName = null; // Only manipulate MapDisplayNodes, since this is the node type for results displayed on the map if (treeViewPlusNode is ESRI.ArcGIS.ADF.Web.UI.WebControls.MapDisplayNode) { ESRI.ArcGIS.ADF.Web.UI.WebControls.MapDisplayNode mapDisplayNode = treeViewPlusNode as ESRI.ArcGIS.ADF.Web.UI.WebControls.MapDisplayNode; // Use the RemoveFromMap function to remove the result graphics from the map. This function returns // the name of the affected map resource. affectedResourceName = mapDisplayNode.RemoveFromMap(TaskResultsInstance); // Add the name of the affected resource to the list if it is not already included if (affectedResourceName != null && !affectedResourceList.Contains(affectedResourceName)) affectedResourceList.Add(affectedResourceName); } // Remove result graphics recursively for any child nodes if (treeViewPlusNode.Nodes.Count > 0) foreach (ESRI.ArcGIS.ADF.Web.UI.WebControls.TreeViewPlusNode childNode in treeViewPlusNode.Nodes) RemoveResultGraphics(childNode, ref affectedResourceList); } // Retrieves the bounding box of a polygon private void GetBoundingExtent(ESRI.ArcGIS.ADF.Web.Geometry.Polygon adfPolygon, ESRI.ArcGIS.ADF.Web.Geometry.Envelope boundingBox) { // Loop through all the rings of the polygon and update the bounding box to account for each vertex for (int i = 0; i < adfPolygon.Rings.Count; ++i) { ESRI.ArcGIS.ADF.Web.Geometry.Ring adfRing = adfPolygon.Rings[i]; for (int j = 0; j < adfRing.Points.Count; ++j) { GetBoundingExtent(adfRing.Points[j], boundingBox); } } } private void GetBoundingExtent(ESRI.ArcGIS.ADF.Web.Geometry.Point adfPoint, ESRI.ArcGIS.ADF.Web.Geometry.Envelope boundingBox) { // Update the passed-in envelope based on whether the passed-in point falls outside the envelope's bounds if (adfPoint.X < boundingBox.XMin) boundingBox.XMin = adfPoint.X; if (adfPoint.X > boundingBox.XMax) boundingBox.XMax = adfPoint.X; if (adfPoint.Y < boundingBox.YMin) boundingBox.YMin = adfPoint.Y; if (adfPoint.Y > boundingBox.YMax) boundingBox.YMax = adfPoint.Y; } #endregion } }