Common Custom JavaScript
Common_CustomJavaScript_CSharp\MapDataGridHover.aspx.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.
// 

public partial class MapDataGridHover : System.Web.UI.Page
{
    #region ASP.NET Page Life Cycle Event Handlers

    protected void Page_Load(object sender, System.EventArgs eventArgs)
    {
        // Get the __EVENTTARGET request parameter.  This will specify any controls that are
        // the target of the event that triggered the Page request (i.e. postback)
        System.Collections.Specialized.NameValueCollection requestParameters =
            Page.Request.Params;
        string controlEvent = null;
        string controlID = requestParameters["__EVENTTARGET"];

        // Check whether the __EVENTTARGET parameter is null or empty and whether it contains the
        // GridView control's ID
        if (!string.IsNullOrEmpty(controlID) && controlID.Contains(GridView1.ID))
        {
            // Get any event arguments from the Page request
            controlEvent = requestParameters["__EVENTARGUMENT"];
            // If the event arguments contain the string indicating initiation of our
            // custom postback event, call the method to zoom to the feature corresponding
            // to the clicked row
            if (controlEvent.Contains("CustomSelect$"))
                SelectRow(controlEvent, "EventID");
        }

        // Make sure the page is not loading as a result of a postback (i.e. is in initial page load)
        if (!IsPostBack)
        {
            // Create table to hold data to link to graphics
            System.Data.DataTable dataTable = new System.Data.DataTable("FireEvents");

            // Create and add columns
            System.Data.DataColumn eventIDDataColumn = new System.Data.DataColumn("EventID");
            System.Data.DataColumn eventInfoDataColumn = new System.Data.DataColumn("EventInfo");
            dataTable.Columns.Add(eventIDDataColumn);
            dataTable.Columns.Add(eventInfoDataColumn);

            // Create, populate, and add three rows
            System.Data.DataRow eventDataRow = dataTable.NewRow();
            eventDataRow[eventIDDataColumn] = 1;
            eventDataRow[eventInfoDataColumn] = "value1";
            dataTable.Rows.Add(eventDataRow);
            
            eventDataRow = dataTable.NewRow();
            eventDataRow[eventIDDataColumn] = 2;
            eventDataRow[eventInfoDataColumn] = "value2";
            dataTable.Rows.Add(eventDataRow);
            
            eventDataRow = dataTable.NewRow();
            eventDataRow[eventIDDataColumn] = 3;
            eventDataRow[eventInfoDataColumn] = "value3";
            dataTable.Rows.Add(eventDataRow);
  
            // Create a dataset and add the table to it
            System.Data.DataSet dataSet = new System.Data.DataSet();
            dataSet.DataSetName = "FireEventsDataSet";
            dataSet.Tables.Add(dataTable);

            // Set the dataset as the GridView's data source and add a handler for the GridView's RowDataBound event
            GridView1.DataSource = dataSet;
            GridView1.RowDataBound += new System.Web.UI.WebControls.GridViewRowEventHandler(GridView1_RowDataBound);

            // Add graphics to the map
            DrawGraphics(dataTable);

            // Bind the GridView to its data source and adjust its appearance
            GridView1.DataBind();
            GridView1.Visible = true;
            GridView1.BorderWidth = 10;
        }
    }

    #endregion

    #region WebControl Event Handlers

    private void GridView1_RowDataBound(object sender, System.Web.UI.WebControls.GridViewRowEventArgs gridViewRowEventArgs)
    {
        // Only manipulate data rows
        if (gridViewRowEventArgs.Row.RowType == System.Web.UI.WebControls.DataControlRowType.DataRow)
        {
            ESRI.ArcGIS.ADF.Web.DataSources.Graphics.MapFunctionality graphicsMapFunctionality =
            (ESRI.ArcGIS.ADF.Web.DataSources.Graphics.MapFunctionality)Map1.GetFunctionality("ADFGraphicsResource");

            string graphicsTableName = Session["graphicsTableName"] as string;
            if (graphicsMapFunctionality.GraphicsDataSet.Tables.Contains(graphicsTableName))
            {
                string datasetName = graphicsMapFunctionality.GraphicsDataSet.DataSetName;

                ESRI.ArcGIS.ADF.Web.Display.Graphics.GraphicsLayer graphicsLayer = 
                    graphicsMapFunctionality.GraphicsDataSet.Tables[graphicsTableName] as 
                    ESRI.ArcGIS.ADF.Web.Display.Graphics.GraphicsLayer;
                string graphicsLayerClientID = Map1.GetGraphicsLayerClientID(graphicsLayer);
                    //string.Format("{0}_{1}", datasetName, graphicsTableName);

                System.Web.UI.WebControls.GridViewRow gridViewRow = gridViewRowEventArgs.Row;

                // The index of the graphic feature is needed to get a reference to the graphic feature client-side.
                // The index of a graphic feature is zero-based, and is determined by the order in which it was added
                // to its graphic feature group.  Here, we can use the gridViewRow's RowIndex, because we know that 
                // the graphic features were added to the graphics layer in the order of the rows of the data table 
                // that is bound to the GridView control
                int graphicFeatureIndex = gridViewRow.RowIndex;

                // Create a JavaScript string that will (1) set the background color of the current
                // row, (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 = "this.style.backgroundColor='{0}';" +
                    "var graphicFeatureGroup = $find('{1}'); " +
                    "var graphicFeature = graphicFeatureGroup.get({2}); " +
                    "graphicFeature.set_highlight({3});";

                // Assign the JavaScript string to the current row's onmouseover event.  Specify the
                // row's background color as gray and the parameter to graphicFeature.set_highlight
                // as true
                gridViewRow.Attributes.Add("onmouseover", string.Format(jsSetRowAndFeatureHighlight,
                    "gray", graphicsLayerClientID, graphicFeatureIndex, "true"));

                // Assign the JavaScript string to the current row's onmouseout event.  Specify the
                // row's background color as white and the parameter to graphicFeature.set_highlight
                // as false
                gridViewRow.Attributes.Add("onmouseout", string.Format(jsSetRowAndFeatureHighlight,
                    "white", graphicsLayerClientID, graphicFeatureIndex, "false"));

                // Construct a JavaScript string that uses Web ADF JavaScript to (1) retrieve the
                // graphicFeatureGroup (i.e. layer) corresponding to the graphics data layer, (2)
                // get the graphicFeature corresponding to the current row, (3) get the geometry of
                // the graphicFeature, (4) get the Page's client-side map object, and (5) zoom to 
                // the graphicFeature
                string jsZoomToFeature = string.Format("var graphicFeatureGroup = $find('{0}'); " +
                    "var graphicFeature = graphicFeatureGroup.get({1}); " +
                    "var geometry = graphicFeature.get_geometry();" +
                    "var map = $find('{2}');" +
                    "map.zoomTo(geometry, .025, true);", graphicsLayerClientID, graphicFeatureIndex, Map1.ClientID);

                // Handle click on client
                gridViewRow.Attributes.Add("onclick", jsZoomToFeature);
                
                // Handle click on server
                //string jsDoPostback = ClientScript.GetPostBackEventReference(gridViewRow, "CustomSelect$" +
                //    gridViewRow.RowIndex);
                //gridViewRow.Attributes.Add("onclick", jsDoPostback);
            }
        }
    }

    #endregion

    #region Instance Methods

    private void DrawGraphics(System.Data.DataTable dataTable)
    {
        // Get the map functionality for the graphics resource
        ESRI.ArcGIS.ADF.Web.DataSources.Graphics.MapFunctionality graphicsMapFunctionality =
            (ESRI.ArcGIS.ADF.Web.DataSources.Graphics.MapFunctionality)Map1.GetFunctionality("ADFGraphicsResource");
        
        // Make sure the graphics have not already been added to the map
        if ((Session["graphicsTableName"] != null) ||
            (graphicsMapFunctionality.GraphicsDataSet.Tables.Contains((string)Session["graphicsTableName"])))
            return;

        // Initialize default symbol
        ESRI.ArcGIS.ADF.Web.Display.Symbol.RasterMarkerSymbol defaultSymbol =
          new ESRI.ArcGIS.ADF.Web.Display.Symbol.RasterMarkerSymbol("images/red_fire.gif");
        defaultSymbol.XOffset = 16;
        defaultSymbol.YOffset = 16;
        defaultSymbol.Height = 32;
        defaultSymbol.Width = 32;
        defaultSymbol.ImageFormat = ESRI.ArcGIS.ADF.Web.ImageFormat.GIF;

        // Create default renderer with default symbol
        ESRI.ArcGIS.ADF.Web.Display.Renderer.SimpleRenderer defaultRenderer =
            new ESRI.ArcGIS.ADF.Web.Display.Renderer.SimpleRenderer(defaultSymbol);

        // Initialize selected symbol
        ESRI.ArcGIS.ADF.Web.Display.Symbol.RasterMarkerSymbol selectedSymbol =
            new ESRI.ArcGIS.ADF.Web.Display.Symbol.RasterMarkerSymbol("images/yellow_fire.gif");
        selectedSymbol.XOffset = 16;
        selectedSymbol.YOffset = 16;
        selectedSymbol.Height = 32;
        selectedSymbol.Width = 32;
        selectedSymbol.ImageFormat = ESRI.ArcGIS.ADF.Web.ImageFormat.GIF;

        // Create selected renderer with selected symbol
        ESRI.ArcGIS.ADF.Web.Display.Renderer.SimpleRenderer selectedRenderer =
            new ESRI.ArcGIS.ADF.Web.Display.Renderer.SimpleRenderer(selectedSymbol);

        // Initialize highlight symbol
        ESRI.ArcGIS.ADF.Web.Display.Symbol.RasterMarkerSymbol highlightSymbol =
            new ESRI.ArcGIS.ADF.Web.Display.Symbol.RasterMarkerSymbol("images/blue_fire.gif");
        highlightSymbol.XOffset = 16;
        highlightSymbol.YOffset = 16;
        highlightSymbol.Height = 32;
        highlightSymbol.Width = 32;
        highlightSymbol.ImageFormat = ESRI.ArcGIS.ADF.Web.ImageFormat.GIF;

        // Create highlight renderer with highlight symbol
        ESRI.ArcGIS.ADF.Web.Display.Renderer.SimpleRenderer highlightRenderer =
            new ESRI.ArcGIS.ADF.Web.Display.Renderer.SimpleRenderer(highlightSymbol);

        // Add a geometry column to the events table
        dataTable.Columns.Add("ADFGeometry", typeof(ESRI.ArcGIS.ADF.Web.Geometry.Geometry));

        // Convert the table to a feature graphics layer
        ESRI.ArcGIS.ADF.Web.Display.Graphics.FeatureGraphicsLayer eventsFeatureGraphicsLayer =
            ESRI.ArcGIS.ADF.Web.Converter.ToGraphicsLayer(dataTable, defaultRenderer, selectedRenderer,
            highlightRenderer, false) as ESRI.ArcGIS.ADF.Web.Display.Graphics.FeatureGraphicsLayer;

        // Assign the layer's name and store it in session
        eventsFeatureGraphicsLayer.TableName = "MyEvents";
        Session["graphicsTableName"] = eventsFeatureGraphicsLayer.TableName;

        // Create a random point geometry for each row in the table underlying the grapics layer
        System.Random randomClass = new System.Random();
        foreach (System.Data.DataRow dataRow in eventsFeatureGraphicsLayer.Rows)
        {
            int x = randomClass.Next(-120, -80);
            int y = randomClass.Next(25, 45);
            ESRI.ArcGIS.ADF.Web.Geometry.Point adfPoint = new ESRI.ArcGIS.ADF.Web.Geometry.Point(x, y);
            adfPoint.SpatialReference = Map1.SpatialReference;
            dataRow[eventsFeatureGraphicsLayer.GeometryColumnName] = adfPoint;
        }

        // Render the graphics layer on the client without callouts (i.e. maptips)
        eventsFeatureGraphicsLayer.RenderOnClient = true;
        eventsFeatureGraphicsLayer.EnableCallout = false;

        // Add the graphics layer to the graphics resource
        graphicsMapFunctionality.GraphicsDataSet.Tables.Add(eventsFeatureGraphicsLayer);

        // Refresh the graphics resource so the new graphics layer appears
        Map1.RefreshResource(graphicsMapFunctionality.Name);
    }

    private void SelectRow(string controlEvent, string uniqueIDFieldName)
    {            
        // Parse the control event string
        string[] controlEventArray = controlEvent.Split('$');
        // Set the selected index of the GridView to the argument of the control event
        GridView1.SelectedIndex = System.Int32.Parse(controlEventArray[1]);
        // Set the text color of the selected row to red
        GridView1.SelectedRowStyle.ForeColor = System.Drawing.Color.Red;

        // Find the column index of the unique ID field
        int uniqueIDFieldIndex = 0;
        foreach (System.Web.UI.WebControls.DataControlField dataControlField in GridView1.Columns)
        {
            if (dataControlField.HeaderText == uniqueIDFieldName)
                break;

            uniqueIDFieldIndex++;
        }

        // Get the value of the unique ID field from the selected row
        string selectedID = GridView1.SelectedRow.Cells[uniqueIDFieldIndex].Text;

        // Get the map functionality for the graphics resource
        ESRI.ArcGIS.ADF.Web.DataSources.Graphics.MapFunctionality graphicsMapFunctionality =
            (ESRI.ArcGIS.ADF.Web.DataSources.Graphics.MapFunctionality)Map1.GetFunctionality("ADFGraphicsResource");

        // Make sure the target graphics layer is present in the graphics resource
        string graphicsTableName = Session["graphicsTableName"] as string;
        if (graphicsMapFunctionality.GraphicsDataSet.Tables.Contains(graphicsTableName))
        {
            // Get the target graphics layer
            ESRI.ArcGIS.ADF.Web.Display.Graphics.GraphicsLayer graphicsLayer =
                graphicsMapFunctionality.GraphicsDataSet.Tables[graphicsTableName]
                as ESRI.ArcGIS.ADF.Web.Display.Graphics.GraphicsLayer;

            // Unselect all features in the graphics layer
            foreach (System.Data.DataRow dataRow in graphicsLayer.Rows)
                dataRow["IS_SELECTED"] = false;

            // Use the event ID of the selected row in the GridView to retrieve the corresponding row in the data table
            // underlying the linked graphics layer
            System.Data.DataRow[] dataRowArray = graphicsLayer.Select(string.Format("EventID = '{0}'", selectedID));

            // Assume that only one row was returned from the select operation, making the first row in the array
            // the one that corresponds to the graphic we wish to select
            System.Data.DataRow selectedDataRow = dataRowArray[0];            
            selectedDataRow["IS_SELECTED"] = true;

            // Get the selected row's geometry
            ESRI.ArcGIS.ADF.Web.Geometry.Geometry adfGeometry = graphicsLayer.GeometryFromRow(selectedDataRow);
        
            // Get the envelope of the geoemtry
            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)
            {
                BoundingExtent((ESRI.ArcGIS.ADF.Web.Geometry.Polygon)adfGeometry, boundingEnvelope);
                // Expand the envelope to include some area around the feature on the map
                boundingEnvelope.Expand(5);
            }
            else if (adfGeometry is ESRI.ArcGIS.ADF.Web.Geometry.Point)
            {
                BoundingExtent((ESRI.ArcGIS.ADF.Web.Geometry.Point)adfGeometry, boundingEnvelope);

                //Map1.CenterAt(new ESRI.ArcGIS.ADF.Web.Geometry.Point(boundingEnvelope.XMin, boundingEnvelope.YMin));

                // 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 = Map1.GetFullExtent().Width / 16;
                boundingEnvelope = new ESRI.ArcGIS.ADF.Web.Geometry.Envelope(
                    boundingEnvelope.XMin - mapWidthSixteenth,
                    boundingEnvelope.YMin - mapWidthSixteenth,
                    boundingEnvelope.XMax + mapWidthSixteenth,
                    boundingEnvelope.YMax + mapWidthSixteenth);
            }

            // Update the map's extent with the envelope
            Map1.Extent = boundingEnvelope;

            // Make sure the map has callback results
            if (Map1.CallbackResults.Count > 0)
            {
                // Register a script block to update the map via the Web ADF processCallbackResult function
                System.Web.UI.ScriptManager.RegisterClientScriptBlock(Page, this.GetType(), "updateMap",
                    string.Format("ESRI.ADF.System.processCallbackResult('{0}');",
                    Map1.CallbackResults.ToString().Replace("//", "////")), true);
            }
        }
    }

    // Retrieves the bounding box of a polygon
    private void BoundingExtent(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)
            {
                BoundingExtent(adfRing.Points[j], boundingBox);
            }
        }
    }

    private void BoundingExtent(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
}