Common Select Buffer tool
Common_SelectBufferTool_CSharp\App_Code\CustomTools.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 CustomComponents
{
    public class SelectTool : ESRI.ArcGIS.ADF.Web.UI.WebControls.Tools.IMapServerToolAction
    {
        #region IMapServerToolAction Members

        void ESRI.ArcGIS.ADF.Web.UI.WebControls.Tools.IMapServerToolAction.ServerAction(
            ESRI.ArcGIS.ADF.Web.UI.WebControls.ToolEventArgs toolEventArgs)
        {
            // Get a reference to the map control on which the tool was executed
            ESRI.ArcGIS.ADF.Web.UI.WebControls.Map adfMap =
                (ESRI.ArcGIS.ADF.Web.UI.WebControls.Map)toolEventArgs.Control;

            try
            {
                // Set the name of the resource on which to perform the selection
                string resourceName = "Data Layers";

                string selectionLayerName = null;
                bool showSelectionInTable;

                // Check whether the page request was issued using a callback or a postback.  A callback is used if no
                // ScriptManager is on the page containing the tool.  Otherwise, a partial postback is used.
                if (adfMap.Page.IsCallback)
                {
                    // Get the callback arguments from the __CALLBACKPARAM argument of the page request parameters
                    string callbackArgumentsString = toolEventArgs.Control.Page.Request.Params["__CALLBACKPARAM"];
                    System.Collections.Specialized.NameValueCollection callbackArgumentsCollection =
                        ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackUtility.ParseStringIntoNameValueCollection(callbackArgumentsString);

                    // Get the value of the selection layer and show in selection table server controls, which were explicitly added to 
                    // the callback arguments via JavaScript in Default.aspx
                    selectionLayerName = callbackArgumentsCollection["ddlSelectionLayer"];
                    showSelectionInTable = bool.Parse(callbackArgumentsCollection["chkSelectionInTable"]);
                }
                else
                {
                    // Get the value of the selection layer and show in selection table server controls, which are automatically 
                    // included in postbacks (partial postbacks included) due to their being server controls
                    selectionLayerName = adfMap.Page.Request.Params["ddlSelectionLayer"];

                    // For the show selection in table checkbox, automatic value is passed as either null (if unchecked) or "on" 
                    // (if checked)
                    if (adfMap.Page.Request.Params["chkSelectionInTable"] == null)
                        showSelectionInTable = false;
                    else
                        showSelectionInTable = true;
                }

                // Get the map extent of the rectangle drawn on the map
                ESRI.ArcGIS.ADF.Web.UI.WebControls.MapRectangleEventArgs mapRectangleEventArgs =
                    (ESRI.ArcGIS.ADF.Web.UI.WebControls.MapRectangleEventArgs)toolEventArgs;
                ESRI.ArcGIS.ADF.Web.Geometry.Envelope adfEnvelope = mapRectangleEventArgs.MapExtent;

                // Get a reference to the resource
                ESRI.ArcGIS.ADF.Web.DataSources.IMapFunctionality commonMapFunctionality =
                    adfMap.GetFunctionality(resourceName);
                ESRI.ArcGIS.ADF.Web.DataSources.IGISResource gisResource = commonMapFunctionality.Resource;

                // Create a query functionality to use in querying 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);

                // Get the resource's queryable layers
                string[] layerIDs = null;
                string[] layerNames = null;
                commonQueryFunctionality.GetQueryableLayers(null, out layerIDs, out layerNames);

                // Get the index of the selection layer in the layer names and ids arrays
                int selectionLayerIndex = 0;
                for (int i = 0; i < layerNames.Length; i++)
                {
                    if (layerNames[i] == selectionLayerName)
                    {
                        if (layerIDs[i] is string)
                        {
                            if (!int.TryParse((string)layerIDs[i], out selectionLayerIndex))
                                selectionLayerIndex = i;
                        }
                        else
                        {
                            selectionLayerIndex = i;
                        }
                        break;
                    }
                }

                // Set-up a spatial filter to use in querying the resource
                ESRI.ArcGIS.ADF.Web.SpatialFilter adfSpatialFilter =
                    new ESRI.ArcGIS.ADF.Web.SpatialFilter();
                adfSpatialFilter.ReturnADFGeometries = true;
                adfSpatialFilter.MaxRecords = 100;
                adfSpatialFilter.Geometry = adfEnvelope;

                // Query the selection layer with the user-drawn rectangle
                System.Data.DataTable resultsDataTable = commonQueryFunctionality.Query(
                    commonMapFunctionality.Name, layerIDs[selectionLayerIndex], adfSpatialFilter);

                if (resultsDataTable.Rows.Count == 0)
                {
                    ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResult noFeaturesFoundCallbackResult = ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResult.CreateJavaScript("alert('No selected features');");
                    adfMap.CallbackResults.Add(noFeaturesFoundCallbackResult);
                }
                // Convert the results data table to a graphics layer
                ESRI.ArcGIS.ADF.Web.Display.Graphics.GraphicsLayer resultsGraphicsLayer =
                    ESRI.ArcGIS.ADF.Web.Converter.ToGraphicsLayer(resultsDataTable,
                    System.Drawing.Color.Yellow, System.Drawing.Color.Green);           

                // Retrieve and clear buffer resource
                ESRI.ArcGIS.ADF.Web.DataSources.IGISFunctionality gisFunctionality =
                    adfMap.GetFunctionality("Buffer");
                ESRI.ArcGIS.ADF.Web.DataSources.Graphics.MapResource bufferGraphicsMapResource =
                    gisFunctionality.Resource as ESRI.ArcGIS.ADF.Web.DataSources.Graphics.MapResource;
                bufferGraphicsMapResource.Graphics.Tables.Clear();

                // Retrieve and clear selection resource
                gisFunctionality = adfMap.GetFunctionality("Selection");
                ESRI.ArcGIS.ADF.Web.DataSources.Graphics.MapResource selectionGraphicsMapResource =
                    gisFunctionality.Resource as ESRI.ArcGIS.ADF.Web.DataSources.Graphics.MapResource;
                selectionGraphicsMapResource.Graphics.Tables.Clear();

                // Add the selection graphics layer to the resource
                selectionGraphicsMapResource.Graphics.Tables.Add(resultsGraphicsLayer);

                // Call method to display or hide the selection table, depending on whether
                // the "Display selection in table" checkbox is checked or not
                CustomToolUtility.DisplayOrHideSelectionTable(adfMap, resultsGraphicsLayer, showSelectionInTable);
                
                // Set the transparency of the selection graphics resource map resource item
                ESRI.ArcGIS.ADF.Web.UI.WebControls.MapResourceItem selectionMapResourceItem = 
                    adfMap.MapResourceManagerInstance.ResourceItems.Find(selectionGraphicsMapResource.Name);
                selectionMapResourceItem.DisplaySettings.Transparency = 50;
                
                // Refresh the selection and buffer resources
                adfMap.RefreshResource(selectionGraphicsMapResource.Name);
                adfMap.RefreshResource(bufferGraphicsMapResource.Name);
            }
            catch (System.Exception exception)
            {
                adfMap.CallbackResults.Add(Utility.GetErrorCallback(exception));
            }
        }
        #endregion
    }

    public class BufferTool : ESRI.ArcGIS.ADF.Web.UI.WebControls.Tools.IMapServerToolAction
    {
        #region IMapServerToolAction Members

        void ESRI.ArcGIS.ADF.Web.UI.WebControls.Tools.IMapServerToolAction.ServerAction(
            ESRI.ArcGIS.ADF.Web.UI.WebControls.ToolEventArgs toolEventArgs)
        {
            ESRI.ArcGIS.ADF.Web.UI.WebControls.Map adfMap = 
                (ESRI.ArcGIS.ADF.Web.UI.WebControls.Map)toolEventArgs.Control;

            try
            {
                ESRI.ArcGIS.ADF.Web.UI.WebControls.MapPointEventArgs mapPointEventArgs = 
                    (ESRI.ArcGIS.ADF.Web.UI.WebControls.MapPointEventArgs)toolEventArgs;
                ESRI.ArcGIS.ADF.Web.Geometry.Point adfPoint = mapPointEventArgs.MapPoint;

                string bufferDistanceString = null;
                string selectionLayerName = null;
                bool showSelectionInTable;

                // Check whether the page request was issued using a callback or a postback.  A callback is used if no
                // ScriptManager is on the page containing the tool.  Otherwise, a partial postback is used.
                if (adfMap.Page.IsCallback)
                {
                    // Get the callback arguments from the __CALLBACKPARAM argument of the page request parameters
                    string callbackArgumentsString = toolEventArgs.Control.Page.Request.Params["__CALLBACKPARAM"];
                    System.Collections.Specialized.NameValueCollection callbackArgumentsCollection =
                        ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackUtility.ParseStringIntoNameValueCollection(callbackArgumentsString);

                    // Get the value of the buffer distance, selection layer, and show in selection table server controls, which were
                    // explicitly added to the tool's arguments via JavaScript in Default.aspx
                    bufferDistanceString = callbackArgumentsCollection["txtBufferDistance"];
                    selectionLayerName = callbackArgumentsCollection["ddlSelectionLayer"];
                    showSelectionInTable = bool.Parse(callbackArgumentsCollection["chkSelectionInTable"]);
                }
                else
                {
                    // Get the value of the buffer distance, selection layer, and show in selection table server controls, which are 
                    // automatically included in postbacks (partial postbacks included) due to their being server controls
                    bufferDistanceString = adfMap.Page.Request.Params["txtBufferDistance"];
                    selectionLayerName = adfMap.Page.Request.Params["ddlSelectionLayer"];

                    // For the show selection in table checkbox, automatic value is passed as either null (if unchecked) or "on" 
                    // (if checked)
                    if (adfMap.Page.Request.Params["chkSelectionInTable"] == null)
                        showSelectionInTable = false;
                    else
                        showSelectionInTable = true;
                }

                // Attempt to retrieve buffer distance from session.  If the attempt fails, initialize
                // buffer distance as 0.
                float bufferDistanceFloat;
                if (!System.Single.TryParse(bufferDistanceString, out bufferDistanceFloat))
                {
                    bufferDistanceFloat = 0.0F;
                }

                // Create an ellipse based on the buffer distance
                System.Drawing.Drawing2D.GraphicsPath graphicsPath = 
                    new System.Drawing.Drawing2D.GraphicsPath();
                graphicsPath.AddEllipse((float)adfPoint.X - (bufferDistanceFloat / 2), 
                    (float)adfPoint.Y - (bufferDistanceFloat / 2), 
                    bufferDistanceFloat, bufferDistanceFloat);

                // Flatten the ellipse.  This will make it appear smooth.
                float flattening = bufferDistanceFloat / 1000;
                graphicsPath.Flatten(null, flattening);

                // Create a Web ADF Point Collection, and add each point in the graphics path to it
                ESRI.ArcGIS.ADF.Web.Geometry.PointCollection adfPointCollection = 
                    new ESRI.ArcGIS.ADF.Web.Geometry.PointCollection();
                foreach (System.Drawing.PointF pointF in graphicsPath.PathPoints)
                {
                    adfPointCollection.Add(new ESRI.ArcGIS.ADF.Web.Geometry.Point(pointF.X, pointF.Y));
                }

                // Construct a Web ADF Polygon containing the buffer by populating a ring with the 
                // buffer point collection, a ring collection with the ring, and a polygon with the 
                // ring collection
                ESRI.ArcGIS.ADF.Web.Geometry.Ring adfRing = new ESRI.ArcGIS.ADF.Web.Geometry.Ring();
                adfRing.Points = adfPointCollection;
                ESRI.ArcGIS.ADF.Web.Geometry.RingCollection adfRingCollection = 
                    new ESRI.ArcGIS.ADF.Web.Geometry.RingCollection();
                adfRingCollection.Add(adfRing);
                ESRI.ArcGIS.ADF.Web.Geometry.Polygon adfBufferPolygon = 
                    new ESRI.ArcGIS.ADF.Web.Geometry.Polygon();
                adfBufferPolygon.Rings = adfRingCollection;

                // Get the graphics resource that will hold the buffer
                ESRI.ArcGIS.ADF.Web.DataSources.IGISFunctionality gisFunctionality =
                    adfMap.GetFunctionality("Buffer");
                ESRI.ArcGIS.ADF.Web.DataSources.Graphics.MapResource bufferGraphicsMapResource =
                    gisFunctionality.Resource as ESRI.ArcGIS.ADF.Web.DataSources.Graphics.MapResource;
                
                // If the resource was not found, throw an exception
                if (bufferGraphicsMapResource == null)
                    throw new System.Exception("Buffer graphics resource not in MapResourceManager");

                // Clear the buffer resource of any previous results
                bufferGraphicsMapResource.Graphics.Tables.Clear();

                // Add an element graphics layer to store the buffer geometry to the resource
                ESRI.ArcGIS.ADF.Web.Display.Graphics.ElementGraphicsLayer elementGraphicsLayer = 
                    new ESRI.ArcGIS.ADF.Web.Display.Graphics.ElementGraphicsLayer();
                bufferGraphicsMapResource.Graphics.Tables.Add(elementGraphicsLayer);

                // Create a graphic element out of the buffer polygon and add it to the 
                // buffer graphics layer
                ESRI.ArcGIS.ADF.Web.Geometry.Geometry adfGeometry = 
                    (ESRI.ArcGIS.ADF.Web.Geometry.Geometry)adfBufferPolygon;
                ESRI.ArcGIS.ADF.Web.Display.Graphics.GraphicElement graphicElement = 
                    new ESRI.ArcGIS.ADF.Web.Display.Graphics.GraphicElement(adfGeometry, 
                    System.Drawing.Color.Green);
                graphicElement.Symbol.Transparency = 70.0;
                elementGraphicsLayer.Add(graphicElement);

                // Get the resource containing the selection layer
                ESRI.ArcGIS.ADF.Web.DataSources.IMapFunctionality commonMapFunctionality = 
                    adfMap.GetFunctionality("Data Layers");
                ESRI.ArcGIS.ADF.Web.DataSources.IGISResource gisResource = 
                    commonMapFunctionality.Resource;

                // Create a query functionality and use it to retrieve the IDs and names of the
                // resource's queryable layers
                ESRI.ArcGIS.ADF.Web.DataSources.IQueryFunctionality commonQueryFunctionality = 
                    (ESRI.ArcGIS.ADF.Web.DataSources.IQueryFunctionality)
                    gisResource.CreateFunctionality(
                    typeof(ESRI.ArcGIS.ADF.Web.DataSources.IQueryFunctionality), null);

                string[] layerIDs;
                string[] layerNames;
                commonQueryFunctionality.GetQueryableLayers(null, out layerIDs, out layerNames);

                // Get the index of the selection layer in the ID and names arrays
                int selectionLayerIndex = 0;
                for (int i = 0; i < layerNames.Length; i++)
                {
                    if (layerNames[i] == selectionLayerName)
                    {
                        selectionLayerIndex = i;
                        break;
                    }
                }

                // Initialize a Web ADF spatial filter with the buffer geometry and use
                // it to query the resource on which the selection will be performed
                ESRI.ArcGIS.ADF.Web.SpatialFilter adfSpatialFilter = 
                    new ESRI.ArcGIS.ADF.Web.SpatialFilter();
                adfSpatialFilter.ReturnADFGeometries = true;
                adfSpatialFilter.MaxRecords = 1000;
                adfSpatialFilter.Geometry = adfBufferPolygon;
                System.Data.DataTable featuresInBufferDataTable = commonQueryFunctionality.Query(
                    null, layerIDs[selectionLayerIndex], adfSpatialFilter);

                if (featuresInBufferDataTable.Rows.Count == 0)
                {
                    ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResult noFeaturesFoundCallbackResult = ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResult.CreateJavaScript("alert('No selected features');");
                    adfMap.CallbackResults.Add(noFeaturesFoundCallbackResult);
                }

                // Convert the query results to a graphics layer
                ESRI.ArcGIS.ADF.Web.Display.Graphics.GraphicsLayer selectionGraphicsLayer =
                    ESRI.ArcGIS.ADF.Web.Converter.ToGraphicsLayer(featuresInBufferDataTable, 
                    System.Drawing.Color.Blue, System.Drawing.Color.Blue);
                
                // Get the graphics resource that will hold the selection and add the selection
                // graphics layer to it
                gisFunctionality = adfMap.GetFunctionality("Selection");
                ESRI.ArcGIS.ADF.Web.DataSources.Graphics.MapResource selectionGraphicsMapResource =
                    gisFunctionality.Resource as ESRI.ArcGIS.ADF.Web.DataSources.Graphics.MapResource;
                selectionGraphicsMapResource.Graphics.Tables.Clear();
                selectionGraphicsMapResource.Graphics.Tables.Add(selectionGraphicsLayer);

                CustomToolUtility.DisplayOrHideSelectionTable(adfMap, selectionGraphicsLayer, showSelectionInTable);

                // Set the transparency of the buffer graphics resource map resource item
                ESRI.ArcGIS.ADF.Web.UI.WebControls.MapResourceItem bufferMapResourceItem =
                    adfMap.MapResourceManagerInstance.ResourceItems.Find(bufferGraphicsMapResource.Name);
                bufferMapResourceItem.DisplaySettings.Transparency = 50;

                // Set the transparency of the selection graphics resource map resource item
                ESRI.ArcGIS.ADF.Web.UI.WebControls.MapResourceItem selectionMapResourceItem =
                    adfMap.MapResourceManagerInstance.ResourceItems.Find(selectionGraphicsMapResource.Name);
                selectionMapResourceItem.DisplaySettings.Transparency = 50;

                adfMap.RefreshResource(bufferGraphicsMapResource.Name);
                adfMap.RefreshResource(selectionGraphicsMapResource.Name);

            }
            catch (System.Exception exception)
            {
                adfMap.CallbackResults.Add(Utility.GetErrorCallback(exception));
            }
        }
        #endregion
    }

    internal class CustomToolUtility
    {
        public static void DisplayOrHideSelectionTable(ESRI.ArcGIS.ADF.Web.UI.WebControls.Map adfMap,
            ESRI.ArcGIS.ADF.Web.Display.Graphics.GraphicsLayer resultsGraphicsLayer, bool showTable)
        {
            try
            {
                // Get the GridView control that will be used to display selection results
                System.Web.UI.WebControls.GridView gridViewResults =
                    (System.Web.UI.WebControls.GridView)adfMap.Page.FindControl("grdSelectionResults");

                System.Web.UI.UpdatePanel updatepanel =
                    (System.Web.UI.UpdatePanel)adfMap.Page.FindControl("UpdatePanel1");

                System.Data.DataTable resultsDataTable = resultsGraphicsLayer;

                // Check whether to show selection results tabularly
                if (showTable)
                {
                    // Make sure results were actually found
                    if (resultsDataTable.Rows.Count > 0)
                    {
                        // Load the graphicsLayer into a new data table and remove the IS_SELECTED column
                        System.Data.DataTable newDataTable = new System.Data.DataTable();
                        newDataTable.Load(resultsGraphicsLayer.CreateDataReader());
                        newDataTable.Columns.Remove("IS_SELECTED");

                        // Bind the results table to the GridView control
                        gridViewResults.DataSource = newDataTable;
                        gridViewResults.DataBind();
                        gridViewResults.Visible = true;
                    }
                    
                    else
                    {

                        gridViewResults.Visible = false;
                    }
                }
                else
                {
                    gridViewResults.Visible = false;
                }
                updatepanel.Update();
            }
            catch (System.Exception exception)
            {
                adfMap.CallbackResults.Add(Utility.GetErrorCallback(exception));
            }

        }
    }
}