Common Add custom tool
Common_AddCustomTool_CSharp\App_Code\CustomToolLibrary.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 CustomToolLibrary
{
    public class ZoomToPointTool : 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 reference to map control
            ESRI.ArcGIS.ADF.Web.UI.WebControls.Map adfMap = (ESRI.ArcGIS.ADF.Web.UI.WebControls.Map)toolEventArgs.Control;

            try
            {
                // Cast tool event arguments to map point event arguments, which allows
                // easy access to the map point clicked by the user
                ESRI.ArcGIS.ADF.Web.UI.WebControls.MapPointEventArgs mapPointEventArgs =
                    (ESRI.ArcGIS.ADF.Web.UI.WebControls.MapPointEventArgs)toolEventArgs;
                // Get the map point from the map point event arguments
                ESRI.ArcGIS.ADF.Web.Geometry.Point adfPoint = mapPointEventArgs.MapPoint;

                // Change map extent.  The resources have not changed in the Map control, thus 
                // a call to Map.Refresh is not required. Note that the Map will generate the 
                // callback response automatically.  You do not need to add the Map's callback 
                // results to any other control or convert them to a string.
                double quarterMapExtentWidth = adfMap.Extent.Width / 4;

                ESRI.ArcGIS.ADF.Web.Geometry.Envelope adfEnvelope =
                    new ESRI.ArcGIS.ADF.Web.Geometry.Envelope(adfPoint.X - quarterMapExtentWidth,
                    adfPoint.Y - quarterMapExtentWidth, adfPoint.X + quarterMapExtentWidth,
                    adfPoint.Y + quarterMapExtentWidth);
                adfMap.Extent = adfEnvelope;
            }
            catch (System.Exception exception)
            {
                // If an error occurred, get the callback result from the ProcessError
                // function and copy to the map control's callback results collection
                adfMap.CallbackResults.Add(Utility.GetErrorCallback(exception));
            }
        }

        #endregion
    }

    public class IdentifyAllTool : 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 reference to the map control
            ESRI.ArcGIS.ADF.Web.UI.WebControls.Map adfMap = 
                (ESRI.ArcGIS.ADF.Web.UI.WebControls.Map)toolEventArgs.Control;

            try
            {
                // Cast tool event arguments to map point event arguments, which allows
                // easy access to the map point clicked by the user
                ESRI.ArcGIS.ADF.Web.UI.WebControls.MapPointEventArgs mapPointEventArgs =
                    (ESRI.ArcGIS.ADF.Web.UI.WebControls.MapPointEventArgs)toolEventArgs;
                // Get the map point from the map point event arguments
                ESRI.ArcGIS.ADF.Web.Geometry.Point adfPoint = mapPointEventArgs.MapPoint;

                // Create a master dataset to store all tables returned from Identity operation
                System.Data.DataSet outputDataset = new System.Data.DataSet();

                // For each map functionality (resource) in the Map, do an Identify
                foreach (ESRI.ArcGIS.ADF.Web.DataSources.IMapFunctionality mapFunctionality
                    in adfMap.GetFunctionalities())
                {
                    // Retrieve the resource for the current map functionality object
                    ESRI.ArcGIS.ADF.Web.DataSources.IGISResource gisResource = mapFunctionality.Resource;

                    // Check whether the current resource supports querying
                    bool supportsQuery = gisResource.SupportsFunctionality(typeof
                        (ESRI.ArcGIS.ADF.Web.DataSources.IQueryFunctionality));

                    if (supportsQuery)
                    {
                        // Create a query functionality object from the current resource
                        ESRI.ArcGIS.ADF.Web.DataSources.IQueryFunctionality queryFunctionality =
                            (ESRI.ArcGIS.ADF.Web.DataSources.IQueryFunctionality)
                            gisResource.CreateFunctionality(typeof(ESRI.ArcGIS.ADF.Web.DataSources.IQueryFunctionality), null);

                        // Get the names and ids of the queryable layers in the current resource
                        string[] layerIDs;
                        string[] layerNames;
                        queryFunctionality.GetQueryableLayers(null, out layerIDs, out layerNames);

                        // Initialize a variable to store tolerance.  This will be used as the tolerance
                        // around the point clicked by the user
                        int pixelTolerance = 3;

                        // Execute the identify operation
                        System.Data.DataTable[] resultDataTableArray = queryFunctionality.Identify(
                            mapFunctionality.Name, adfPoint, pixelTolerance,
                            ESRI.ArcGIS.ADF.Web.IdentifyOption.VisibleLayers, layerIDs);

                        // Exit the loop if no results were found
                        if (resultDataTableArray == null)
                            break;

                        // Add each table returned to the master dataset.  Give each table a unique name
                        // composed of the resource name, layer id, and layer name.
                        for (int index = 0; index < resultDataTableArray.Length; index++)
                        {
                            System.Data.DataTable resultDataTable = resultDataTableArray[index];
                            // Find the index of the layer name in the layerNames array
                            // corresponding to the current results table
                            int i;
                            for (i = 0; i < layerNames.Length; i++)
                            {
                                if (resultDataTable.TableName == layerNames[i])
                                    break;
                            }
                            resultDataTable.TableName = gisResource.Name + "_" + layerIDs[i] + "_" +
                                layerNames[i];
                            outputDataset.Tables.Add(resultDataTable);
                        }
                    }
                }


                // For each table in the master dataset, create a GridView to display the content.  Write the rendered
                // HTML content to a string for dynamic display in the browser
                System.Data.DataTableCollection outputDataTableCollection = outputDataset.Tables;
                string tableHTMLString = string.Empty;
                foreach (System.Data.DataTable dataTable in outputDataTableCollection)
                {
                    if (dataTable.Rows.Count == 0)
                        continue;
                    System.Web.UI.WebControls.GridView gridView = new System.Web.UI.WebControls.GridView();
                    gridView.ToolTip = dataTable.TableName;
                    gridView.Caption = dataTable.TableName;
                    gridView.DataSource = dataTable;
                    gridView.DataBind();
                    gridView.Visible = true;
                    gridView.BorderWidth = 10;

                    using (System.IO.StringWriter stringWriter = new System.IO.StringWriter())
                    {
                        System.Web.UI.HtmlTextWriter htmlTextWriter =
                            new System.Web.UI.HtmlTextWriter(stringWriter);
                        gridView.RenderControl(htmlTextWriter);
                        htmlTextWriter.Flush();
                        tableHTMLString = tableHTMLString + stringWriter.ToString();
                    }
                }

                // Use ADF callback mechanism to insert content into a div element in the page
                ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResult tablesCallbackResult =
                    ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResult.CreateSetInnerContent(
                    "datadiv", tableHTMLString);

                adfMap.CallbackResults.Add(tablesCallbackResult);
            }
            catch (System.Exception exception)
            {
                // If an error occurred, get the callback result from the ProcessError
                // function and copy to the map control's callback results collection
                adfMap.CallbackResults.Add(Utility.GetErrorCallback(exception));
            }

        }
        #endregion
    }

    public class ExtentCommand : ESRI.ArcGIS.ADF.Web.UI.WebControls.Tools.IMapServerCommandAction
    {
        #region IMapServerCommandAction Members

        void ESRI.ArcGIS.ADF.Web.UI.WebControls.Tools.IServerAction.ServerAction(
            ESRI.ArcGIS.ADF.Web.UI.WebControls.Tools.ToolbarItemInfo toolbarItemInfo)
        {
            // Change map extent.  Since layer or resource content is 
            // not changed, no call to Map.Refresh is needed.
            ESRI.ArcGIS.ADF.Web.UI.WebControls.Map adfMap = 
                (ESRI.ArcGIS.ADF.Web.UI.WebControls.Map)toolbarItemInfo.BuddyControls[0];

            try
            {
                adfMap.Extent = new ESRI.ArcGIS.ADF.Web.Geometry.Envelope(-120, 30, -100, 40);
            }
            catch (System.Exception exception)
            {
                // If an error occurred, get the callback result from the ProcessError
                // function and copy to the map control's callback results collection
                adfMap.CallbackResults.Add(Utility.GetErrorCallback(exception));
            }
        }

        #endregion
    }

    public class ExtentListDropDownBox : ESRI.ArcGIS.ADF.Web.UI.WebControls.Tools.IMapServerDropDownBoxAction
    {
        #region IMapServerDropDownBoxAction Members

        void ESRI.ArcGIS.ADF.Web.UI.WebControls.Tools.IServerAction.ServerAction(
            ESRI.ArcGIS.ADF.Web.UI.WebControls.Tools.ToolbarItemInfo toolbarItemInfo)
        {
            // Get the value selected in Web ADF drop down box.  Change map extent and set Map.Extent to the new extent.
            // Get the Web ADF map control
            ESRI.ArcGIS.ADF.Web.UI.WebControls.Map adfMap = 
                (ESRI.ArcGIS.ADF.Web.UI.WebControls.Map)toolbarItemInfo.BuddyControls[0];

            try
            {
                // Get the direction drop-down box and the currently selected value
                ESRI.ArcGIS.ADF.Web.UI.WebControls.DropDownBox directionDropDownBox =
                    (ESRI.ArcGIS.ADF.Web.UI.WebControls.DropDownBox)toolbarItemInfo.Toolbar.ToolbarItems.Find(toolbarItemInfo.Name);
                string directionQuadrant = directionDropDownBox.SelectedValue;

                // Get the current map extent parameters
                double minx, miny, maxx, maxy;
                minx = adfMap.Extent.XMin;
                miny = adfMap.Extent.YMin;
                maxx = adfMap.Extent.XMax;
                maxy = adfMap.Extent.YMax;

                // Calculate the width and height of the current map extent
                double xWidth = maxx - minx;
                double yHeight = maxy - miny;

                // Calculate new extent parameters based on the currently selected
                // value in the direction drop-down box
                switch (directionQuadrant)
                {
                    case "NorthWest":
                        miny = maxy;
                        maxy = maxy + yHeight;
                        maxx = minx;
                        minx = minx - xWidth;
                        break;
                    case "NorthEast":
                        minx = maxx;
                        maxx = maxx + xWidth;
                        miny = maxy;
                        maxy = maxy + yHeight;
                        break;
                    case "SouthWest":
                        maxx = minx;
                        minx = minx - xWidth;
                        maxy = miny;
                        miny = miny - yHeight;
                        break;
                    case "SouthEast":
                        minx = maxx;
                        maxx = maxx + xWidth;
                        maxy = miny;
                        miny = miny - yHeight;
                        break;
                }

                // Set the map control's extent to the new extent parameters
                adfMap.Extent = new ESRI.ArcGIS.ADF.Web.Geometry.Envelope(minx, miny, maxx, maxy);
            }
            catch (System.Exception exception)
            {
                // If an error occurred, get the callback result from the ProcessError
                // function and copy to the map control's callback results collection
                adfMap.CallbackResults.Add(Utility.GetErrorCallback(exception));
            }
        }

        #endregion
    }

    public class HyperLinkTool : 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 map control from passed-in arguments
            ESRI.ArcGIS.ADF.Web.UI.WebControls.Map adfMap = 
                (ESRI.ArcGIS.ADF.Web.UI.WebControls.Map)toolEventArgs.Control;

            // Cast tool event arguments to map point event arguments, which allows
            // easy access to the map point clicked by the user
            ESRI.ArcGIS.ADF.Web.UI.WebControls.MapPointEventArgs mapPointEventArgs =
                (ESRI.ArcGIS.ADF.Web.UI.WebControls.MapPointEventArgs)toolEventArgs;
            // Get the map point from the map point event arguments
            ESRI.ArcGIS.ADF.Web.Geometry.Point adfPoint = mapPointEventArgs.MapPoint;

            // Get the functionality of the resource that contains the layer on which you want to hyperlink
            ESRI.ArcGIS.ADF.Web.DataSources.IMapFunctionality commonMapFunctionality = 
                adfMap.GetFunctionality("Server Resource");
            ESRI.ArcGIS.ADF.Web.DataSources.IGISResource gisResource = commonMapFunctionality.Resource;

            // Create query functionality from the resource
            ESRI.ArcGIS.ADF.Web.DataSources.IQueryFunctionality queryFunctionality =
                (ESRI.ArcGIS.ADF.Web.DataSources.IQueryFunctionality)gisResource.CreateFunctionality
                (typeof(ESRI.ArcGIS.ADF.Web.DataSources.IQueryFunctionality), null);

            // Get the ids and names of the layers in the current that can be queried
            string[] layerIDs;
            string[] layerNames;
            queryFunctionality.GetQueryableLayers(null, out layerIDs, out layerNames);

            // Set the layer name on which you want to hyperlink
            string activeLayerName = "states";

            // Iterate through the layer names until a match is found for
            // activeLayerName.  Include a call to ToUpper() in the comparison
            // to eliminate case sensitivity.
            string activeLayerID = null;
            for (int index = 0; index < layerNames.Length; index++)
            {
                if (layerNames[index].ToUpper() == activeLayerName.ToUpper())
                {
                    // Get the layer id of the match found from the layer id array
                    activeLayerID = layerIDs[index];
                    break;
                }
            }

            // Create a spatial filter and initialize its geometry with the point clicked
            ESRI.ArcGIS.ADF.Web.SpatialFilter spatialFilter = new ESRI.ArcGIS.ADF.Web.SpatialFilter();
            spatialFilter.Geometry = adfPoint;

            try
            {
                // Execute the query
                System.Data.DataTable resultDataTable =
                    queryFunctionality.Query(commonMapFunctionality.Name, activeLayerID, spatialFilter);

                // If no features returned, show alert
                if (resultDataTable.Rows.Count < 1)
                {
                    throw new System.Exception("No feature found");
                }

                // Name of field containing the term to the google search url
                string searchName = (string)resultDataTable.Rows[0]["STATE_NAME"];

                // If field contains no data, show alert
                if (string.IsNullOrEmpty(searchName))
                {
                    throw new System.Exception("Hyperlink field contains no data");
                }

                // Construct the JavaScript call to change the map cursor back to original
                string jsChangeCursor = "map.divObject.style.cursor = map.cursor";
                
                // Create a callback result containing the JavaScript call and add to the
                // map control's callback results collection
                ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResult cursorCallbackResult =
                    ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResult.CreateJavaScript(jsChangeCursor);
                adfMap.CallbackResults.Add(cursorCallbackResult);
                
                // Construct the JavaScript call to open a new browser window.  Any valid url can be used.
                string jsPopup = "window.open('http://www.google.com/search?q=" + searchName + "');";
                
                // Create a callback result containing the JavaScript call and add to the
                // map control's callback results collection
                ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResult popupCallbackResult =
                    ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResult.CreateJavaScript(jsPopup);
                adfMap.CallbackResults.Add(popupCallbackResult);
            }
            catch (System.Exception exception)
            {
                // If an error occurred, get the callback result from the ProcessError
                // function and copy to the map control's callback results collection
                adfMap.CallbackResults.Add(Utility.GetErrorCallback(exception));
            }

        }
        
        #endregion
    }

    public class PreviousExtent : ESRI.ArcGIS.ADF.Web.UI.WebControls.Tools.IMapServerCommandAction
    {
        #region IMapServerCommandAction Members

        void ESRI.ArcGIS.ADF.Web.UI.WebControls.Tools.IServerAction.ServerAction(
            ESRI.ArcGIS.ADF.Web.UI.WebControls.Tools.ToolbarItemInfo toolbarItemInfo)
        {
            ESRI.ArcGIS.ADF.Web.UI.WebControls.Map adfMap = 
                (ESRI.ArcGIS.ADF.Web.UI.WebControls.Map)toolbarItemInfo.BuddyControls[0];

            try
            {
                // Access to custom members in a page.  Implement custom interface in the Page.
                IBaseToolbarRefresh baseToolbarRefresh = (IBaseToolbarRefresh)adfMap.Page;

                // A previous\next action is occurring
                // Initial previous\next action to skip extent hashtable adjustment
                adfMap.Page.Session["previousNext"] = true;
                // Subsequent map draw from previous\next action to skip extent hashtable adjustment
                adfMap.Page.Session["previousNextMapHandler"] = true;
                System.Collections.Hashtable extentsHashTable = null;

                // If there is an extent history, continue
                if (adfMap.Page.Session["extentHistory"] != null)
                {
                    // Get the extent history
                    extentsHashTable = (System.Collections.Hashtable)adfMap.Page.Session["extentHistory"];

                    // Get the current extent index.  If greater than 0, decrement the index
                    // and set the map extent to the previous extent in the extent history.               
                    int extentIndex = (int)adfMap.Page.Session["currentExtentIndex"];

                    if (extentIndex > 0)
                    {
                        extentIndex--;
                        adfMap.Page.Session["currentExtentIndex"] = extentIndex;
                        adfMap.Extent = (ESRI.ArcGIS.ADF.Web.Geometry.Envelope)extentsHashTable[extentIndex];                        
                    }

                    // If the index is now less than or equal to 0, meaning there is not prior extent
                    // in the extent history, disable the previous extent command.
                    if (extentIndex <= 0)
                    {
                        baseToolbarRefresh.RefreshToolbar("previousExtent", true);
                    }
                }
                // If there is an extent history, always enable the next extent command after the previous
                // extent command is executed.
                baseToolbarRefresh.RefreshToolbar("nextExtent", false);
            }
            catch (System.Exception exception)
            {
                // If an error occurred, get the callback result from the ProcessError
                // function and copy to the map control's callback results collection
                adfMap.CallbackResults.Add(Utility.GetErrorCallback(exception));
            }
        }

        #endregion
    }

    public class NextExtent : ESRI.ArcGIS.ADF.Web.UI.WebControls.Tools.IMapServerCommandAction
    {
        #region IMapServerCommandAction Members

        void ESRI.ArcGIS.ADF.Web.UI.WebControls.Tools.IServerAction.ServerAction(
            ESRI.ArcGIS.ADF.Web.UI.WebControls.Tools.ToolbarItemInfo toolbarItemInfo)
        {
            // Get references to the map control and page via IBaseToolbarRefresh
            ESRI.ArcGIS.ADF.Web.UI.WebControls.Map adfMap = 
                (ESRI.ArcGIS.ADF.Web.UI.WebControls.Map)toolbarItemInfo.BuddyControls[0];

            try
            {
                IBaseToolbarRefresh baseToolbarRefresh = (IBaseToolbarRefresh)adfMap.Page;

                // A previous\next action is occurring
                // Initial previous\next action to skip extent hashtable adjustment
                adfMap.Page.Session["previousNext"] = true;
                // Subsequent map draw from previous\next action to skip extent hashtable adjustment
                adfMap.Page.Session["previousNextMapHandler"] = true;
                System.Collections.Hashtable extentsHashTable = null;

                // If there is an extent history, continue
                if (adfMap.Page.Session["extentHistory"] != null)
                {
                    // Get the extent history and current extent index
                    extentsHashTable = (System.Collections.Hashtable)adfMap.Page.Session["extentHistory"];
                    int extentIndex = (int)adfMap.Page.Session["currentExtentIndex"];

                    // Get the current extent index.  If index is less than the index of the last extent in extent history, 
                    // increment the index by 1 and set the map extent to the next extent in the extent history.
                    if (extentIndex < (extentsHashTable.Count - 1))
                    {
                        extentIndex++;
                        adfMap.Page.Session["currentExtentIndex"] = extentIndex;
                        adfMap.Extent = (ESRI.ArcGIS.ADF.Web.Geometry.Envelope)extentsHashTable[extentIndex];
                    }

                    // If the index greater than or equal to the index of the last extent in extent history,
                    // meaning there is not another extent to move to, disable the next extent command.
                    if (extentIndex >= (extentsHashTable.Count - 1))
                    {
                        baseToolbarRefresh.RefreshToolbar("nextExtent", true);
                    }

                    // If there is an extent history, always enable the previous extent command after the 
                    // next extent command is executed.
                    baseToolbarRefresh.RefreshToolbar("previousExtent", false);
                }
            }
            catch (System.Exception exception)
            {
                // If an error occurred, get the callback result from the ProcessError
                // function and copy to the map control's callback results collection
                adfMap.CallbackResults.Add(Utility.GetErrorCallback(exception));
            }
        }

        #endregion
    }

    public class Utility
    {
        // Constructs a callback result that will display an error message based on the passed-in
        // exception
        public static ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResult GetErrorCallback(
            System.Exception exception)
        {
            // Create a callback result to display an error message
            string jsAlertErrorMessage = GetJavaScriptErrorString(exception);
            ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResult alertCallbackResult =
                ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResult.CreateJavaScript(jsAlertErrorMessage);
            return alertCallbackResult;
        }

        // Constructs JavaScript necessary to display an error message based on the passed-in exception.
        public static string GetJavaScriptErrorString(System.Exception exception)
        {
            // Get the website's configuration file
            System.Configuration.Configuration webConfig =
            System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration(
                System.Web.HttpContext.Current.Request.ApplicationPath);

            // Get the "compilation" section of the config file
            System.Web.Configuration.CompilationSection compilationSection =
                webConfig.GetSection("system.web/compilation") as
                System.Web.Configuration.CompilationSection;

            // If the config file's compilation section specifies debug mode, include 
            // stack trace information in the error message.  Otherwise, just return 
            // the exception message.
            string errorMessage = null;
            if ((compilationSection != null) && (compilationSection.Debug))
            {
                string stackTrace = exception.StackTrace.Replace("\\", "\\\\");
                errorMessage = exception.Message + "\\n\\n" + stackTrace.Trim();
            }
            else
                errorMessage = exception.Message;

            // Create a callback result to display an error message
            string jsAlertException = "alert('" + errorMessage + "')";
            return jsAlertException;
        }
    }
}