CustomControls_CSharp\ADFWebPart\MapGridViewWebPart.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 ADFWebPart { // Comments following "///" are recognized as XML documentation comments. Different documentation // comment types can be specified by using different tags. Some comment types, such as <summary> // and <param>, show up in Intellisense, while others, such as <remarks> show up in the Object // Browser. XML documentation files can be generated from classes containing such documentation. /// <summary> /// WebPart containing an ArcGIS Server Web ADF Map Control with a linked GridView /// </summary> /// <remarks> /// The web part's grid view displays data in the current map extent for a user-specified /// layer in a user-specified resource. Hovering over a grid view row highlights the /// corresponding map feature, and clicking on the row zooms to the feature. /// /// <para>Note that, for the map to initialize properly, a valid ArcGIS Server geometry /// service URL must be specified, either via the constructor or the GeometryServiceUrl /// property.</para> /// </remarks> [System.Web.UI.ToolboxData("<{0}:MapGridViewWebPart runat=\"server\"></{0}:MapGridViewWebPart>")] [System.ComponentModel.Designer(typeof(ADFWebPart.MapGridViewWebPartDesigner), typeof(System.ComponentModel.Design.IDesigner))] public class MapGridViewWebPart : AJAXSharePointWebPart { #region Instance Variable Declarations private ESRI.ArcGIS.ADF.Web.UI.WebControls.Map m_adfMap = null; private ESRI.ArcGIS.ADF.Web.UI.WebControls.MapResourceManager m_mapResourceManager = null; private System.Web.UI.UpdatePanel m_updatePanel = null; private string m_graphicsDataLayerName = null; private System.Web.UI.WebControls.GridView m_dataLayerGridView = null; private bool m_gridViewDataBound = false; private bool m_hasScriptManager = false; private string m_graphicsMapResourceID; private string m_dataLayerMapResourceID; private string m_backgroundMapResourceID; private string m_dataSourceType; private string m_userDataSource; private string m_mapResourceDefinition; private string m_dataLayerName; private string m_geometryServiceUrl; private int m_maxFeatures; private System.Collections.Specialized.NameValueCollection m_fieldsCollection; #endregion #region Constructors /// <summary> /// Creates a new, uninitialized instance of the MapGridViewWebPart class. /// </summary> public MapGridViewWebPart() { // Default property values m_dataSourceType = "ArcGIS Server Internet"; m_userDataSource = "http://serverapps.esri.com/arcgis/services/SamplesNET"; // SanFrancisco.mxd in <ArcGIS Developer Kit Install>\Samples\data\SanFrancisco m_mapResourceDefinition = "1@Layers@SanFrancisco"; m_dataLayerName = "customers"; m_graphicsDataLayerName = m_dataLayerName + "_Graphics"; m_geometryServiceUrl = "http://serverapps.esri.com/arcgis/services/Geometry/GeometryServer"; m_maxFeatures = 20; // Initialize a NameValueCollection to specify how we want fields to be displayed. This specifies the // field display for both the WebPart's GridView and callouts when features are hovered over. m_fieldsCollection = new System.Collections.Specialized.NameValueCollection(); m_fieldsCollection.Add("NAME", "Site Name"); m_fieldsCollection.Add("ADDRESS", "Address"); //m_fieldsCollection.Add("SALES", "Sales"); } /// <summary> /// Instantiates a fully parameterized MapGridViewWebPart /// </summary> /// <param name="dataSource">Machine name or URL that specifies the host of the ArcGIS /// server service</param> /// <param name="resourceDefinition">Service to use in the format /// <DataFrameName>@<ServiceName></param> /// <param name="resourceType">"ArcGIS Server Local" or "ArcGIS Server Internet"</param> /// <param name="dataLayerName">Layer for which data will be displayed in the GridView</param> /// <param name="geometryServiceUrl">URL of an ArcGIS Server Geometry Service</param> public MapGridViewWebPart(string dataSource, string resourceDefinition, string resourceType, string dataLayerName, string geometryServiceUrl) { m_userDataSource = dataSource; m_mapResourceDefinition = resourceDefinition; m_dataSourceType = resourceType; m_dataLayerName = dataLayerName; m_graphicsDataLayerName = m_dataLayerName + "_Graphics"; m_geometryServiceUrl = geometryServiceUrl; } #endregion #region WebControl Life Cycle Event Handlers protected override void OnInit(System.EventArgs e) { base.OnInit(e); m_graphicsMapResourceID = "GraphicsMapResource<!--" + this.UniqueID + "-->"; m_dataLayerMapResourceID = "AGSMapResource<!--" + this.UniqueID + "-->"; m_backgroundMapResourceID = "AGSBackground<!--" + this.UniqueID + "-->"; //Make sure there is a script manager on the page if (System.Web.UI.ScriptManager.GetCurrent(this.Page) != null) { m_hasScriptManager = true; } } // Handles custom postback row click event, if enabled protected override void OnLoad(System.EventArgs e) { base.OnLoad(e); // Make sure the page has a script manager if (propertyCheck()) { // 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"]; // Make sure the event target is not null or empty and that it contains the ID of // the web part's GridView // Ensure child controls are created before checked EnsureChildControls(); if (!string.IsNullOrEmpty(controlID) && controlID.Contains(m_dataLayerGridView.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 select the clicked row if (controlEvent.Contains("SelectClickedRow$")) SelectRow(controlEvent); } } } // Creates the controls contained in the WebPart - A Map, GridView, and UpdatePanel protected override void CreateChildControls() { try { base.CreateChildControls(); // Make sure the page has a ScriptManager. This is required for managing the // asynchronous Map-GridView interaction via an UpdatePanel if (propertyCheck()) { // Create the MapResourceManager that will be used by the WebPart's Map m_mapResourceManager = new ESRI.ArcGIS.ADF.Web.UI.WebControls.MapResourceManager(); m_mapResourceManager.ID = "webPartMapResourceManager"; Controls.Add(m_mapResourceManager); // Create the WebPart's Map Control m_adfMap = new ESRI.ArcGIS.ADF.Web.UI.WebControls.Map(); m_adfMap.ID = this.ID + "_webPartMap"; m_adfMap.Visible = true; m_adfMap.Height = 300; m_adfMap.Width = 300; m_adfMap.Style.Add("position", "relative"); m_adfMap.Style.Add("top", "0px"); m_adfMap.Style.Add("left", "0px"); m_adfMap.MapResourceManager = m_mapResourceManager.UniqueID; m_adfMap.ExtentChanged += new ESRI.ArcGIS.ADF.Web.UI.WebControls.MapExtentChangeEventHandler( Map_ExtentChanged); // Create an HTML table to hold the Map and GridView System.Web.UI.WebControls.Table table = new System.Web.UI.WebControls.Table(); table.Width = new System.Web.UI.WebControls.Unit(100, System.Web.UI.WebControls.UnitType.Percentage); // Add a row to the table System.Web.UI.WebControls.TableRow tableRow; tableRow = new System.Web.UI.WebControls.TableRow(); table.Rows.Add(tableRow); // Add a cell to the table and put the Map in it System.Web.UI.WebControls.TableCell tableCell; tableCell = new System.Web.UI.WebControls.TableCell(); tableCell.Style[System.Web.UI.HtmlTextWriterStyle.VerticalAlign] = "top"; tableRow.Cells.Add(tableCell); tableCell.Controls.Add(m_adfMap); // Create the GridView m_dataLayerGridView = CreateGridView(); // Create an update panel to hold the GridView m_updatePanel = new System.Web.UI.UpdatePanel(); m_updatePanel.ID = this.ID + "_updatePanel"; m_updatePanel.ChildrenAsTriggers = true; m_updatePanel.UpdateMode = System.Web.UI.UpdatePanelUpdateMode.Conditional; // Create a trigger to wire the GridView to the map's extent changed event System.Web.UI.AsyncPostBackTrigger mapTrigger = new System.Web.UI.AsyncPostBackTrigger(); // Set the trigger control to be the Map mapTrigger.ControlID = this.ID + "_webPartMap"; // Set the trigger event to ExtentChanged mapTrigger.EventName = "ExtentChanged"; // Add the trigger to the update panel m_updatePanel.Triggers.Add(mapTrigger); // Add the GridView to the UpdatePanel m_updatePanel.ContentTemplateContainer.Controls.Add(m_dataLayerGridView); // Create another table cell, add it to the current table row, and put the // UpdatePanel containing the GridView in it tableCell = new System.Web.UI.WebControls.TableCell(); tableCell.Style[System.Web.UI.HtmlTextWriterStyle.VerticalAlign] = "top"; tableRow.Cells.Add(tableCell); tableCell.Controls.Add(m_updatePanel); Controls.Add(table); } else { // Create a label stating that this web part requires a ScriptManager. A more // robust implemenation could include web part configuration with the Callback // Framework if a ScriptManager is unavailable. if (!m_hasScriptManager) { System.Web.UI.WebControls.Label noScriptManagerLabel = new System.Web.UI.WebControls.Label(); noScriptManagerLabel.ID = "lblNoScriptManager"; noScriptManagerLabel.Text = "A Script Manager must exist on the page for this web " + "part to be used."; Controls.Add(noScriptManagerLabel); } else { System.Web.UI.WebControls.Label noResourceDefLabel = new System.Web.UI.WebControls.Label(); noResourceDefLabel.ID = "lblNoResourceDef"; noResourceDefLabel.Text = "Data source type and definition, resource definition, and data layer name must be defined."; Controls.Add(noResourceDefLabel); } } } catch (System.Exception ex) { System.Diagnostics.Debug.Write(ex.Message); } } // Executes before the control is rendered protected override void OnPreRender(System.EventArgs e) { base.OnPreRender(e); if (propertyCheck()) { // Add resources to the map resource manager ESRI.ArcGIS.ADF.Web.UI.WebControls.MapResourceItem mapResourceItem = AddResourcesToMapResourceManager(); // Initialize the map's extent based on the user-specified data layer if (m_mapResourceManager != null && mapResourceItem != null) { InitializeMapExtent(mapResourceItem); } // Check whether the WebPart user has specified fields for display m_dataLayerGridView.Columns.Clear(); if (m_fieldsCollection != null) { // Create BoundFields for each of the fields specified by the user and add them to the GridView for (int i = 0; i < m_fieldsCollection.Count; i++) { System.Web.UI.WebControls.BoundField boundField = new System.Web.UI.WebControls.BoundField(); boundField.DataField = m_fieldsCollection.GetKey(i); boundField.SortExpression = m_fieldsCollection.GetKey(i); boundField.HeaderText = m_fieldsCollection[i]; m_dataLayerGridView.Columns.Add(boundField); } // Since we have explicitly specified fields for display, we do not want the GridView to // generate its own fields m_dataLayerGridView.AutoGenerateColumns = false; } else { // Since the user has not specified fields, we specify that the GridView should generate // columns automatically based on the data to which it is bound m_dataLayerGridView.AutoGenerateColumns = true; } // Get the functionality for the graphics resource ESRI.ArcGIS.ADF.Web.DataSources.Graphics.MapFunctionality graphicsMapFunctionality = (ESRI.ArcGIS.ADF.Web.DataSources.Graphics.MapFunctionality)m_adfMap.GetFunctionality( m_graphicsMapResourceID); // If the graphics resource exists and already contains a table with the graphics data layer // name then we don't want to execute the code to create the graphics layer if ((graphicsMapFunctionality != null) && !graphicsMapFunctionality.GraphicsDataSet.Tables.Contains(m_graphicsDataLayerName)) { // Get the total number of features in the data layer by passing in a null // extent to GetDataLayerFeaturesInExtent and temporarily setting the // member variable specifying the maximum number of features to the // maximum for the integer data type. int maxFeatures = m_maxFeatures; m_maxFeatures = int.MaxValue; System.Data.DataTable resultsDataTable = GetDataLayerFeaturesInExtent(null); m_adfMap.Page.Session["totalDataLayerFeatures"] = resultsDataTable.Rows.Count; m_maxFeatures = maxFeatures; // Initialize the graphics data layer. If the total number of features in the // user-specified data layer is less than the maximum features property, then // all of the data layer features can be included in the graphics layer. We // therefore pass in a null extent to GetDataLayerFeaturesInExtent so that all // the features in the data layer are included in the data table on which the // graphics layer is based. In this case, the graphics layer is only created // here. If the total number of features is greater than the maximum features // property, then we limit the features in the data table to those in the // initial map extent. In this case, since not all of the features can be // included in the graphics layer at once, the graphics layer will be recreated // every time the map extent is changed. if (resultsDataTable.Rows.Count <= m_maxFeatures) resultsDataTable = GetDataLayerFeaturesInExtent(null); else resultsDataTable = GetDataLayerFeaturesInExtent(m_adfMap.Extent); CreateGraphicsDataLayer(resultsDataTable); m_dataLayerGridView.DataSource = resultsDataTable; m_dataLayerGridView.DataBind(); } // If a user navigates away from the page and returns during the same session, the GridView needs to bind to // the data again. The m_gridViewDataBound variable tracks if the GridView has bound to the data. else if (!m_gridViewDataBound) { try { // Get the data layer features in the new extent and update the graphics data // layer accordingly System.Data.DataTable queryResultsDataTable = GetDataLayerFeaturesInExtent(m_adfMap.Extent); // If the total number of features in the data layer is greater than the max features property, // then we need to recreate the data graphics layer. Otherwise, the records in // queryResultsDataTable (which will be displayed on the WebPart's GridView) may include records // that are not in the graphics layer if ((m_adfMap.Page.Session["totalDataLayerFeatures"] != null) && ((int)m_adfMap.Page.Session["totalDataLayerFeatures"] > m_maxFeatures)) CreateGraphicsDataLayer(queryResultsDataTable); // Store the results table in session for use when the GridView is paging string resultsTableSessionKey = string.Format("{0}_queryResultsDataTable", this.ID); Page.Session[resultsTableSessionKey] = queryResultsDataTable; // Initialize the data source of the WebPart's GridView with the query results m_dataLayerGridView.DataSource = queryResultsDataTable; // Turn on paging m_dataLayerGridView.PageSize = 5; m_dataLayerGridView.AllowPaging = true; m_dataLayerGridView.PagerTemplate = null; // Bind the data source to the GridView m_dataLayerGridView.DataBind(); } catch (System.Exception ex) { System.Diagnostics.Debug.WriteLine(ex.Message); } } } } // Renders the web control on the page protected override void RenderContents(System.Web.UI.HtmlTextWriter writer) { // Check whether the control is being rendered at design-time or run-time if (DesignMode) { // Since the control is being rendered at design-time, we will generate a label // showing the control's ID, the control's type, and, if no ScriptManager is // present, a warning that one is required // Initialize a label with the control ID System.Web.UI.WebControls.Label IDLabel = new System.Web.UI.WebControls.Label(); IDLabel.Font.Name = "Verdana"; IDLabel.Font.Size = 9; IDLabel.Text = " " + this.ID + "<br /><br />"; // Render the label IDLabel.RenderControl(writer); // Initialize a label with the control type System.Web.UI.WebControls.Label typeLabel = new System.Web.UI.WebControls.Label(); typeLabel.Font.Name = "Verdana"; typeLabel.Font.Size = 9; typeLabel.Text = " MapGridViewWebPart<br /><br />"; // Render the label typeLabel.RenderControl(writer); // Check whether the Page contains a script manager bool hasScriptManager = HasControlOfType( typeof(System.Web.UI.ScriptManager), Page.Controls); if (!hasScriptManager) { // Format warning labels // Create a label in red, bold font for the warning title System.Web.UI.WebControls.Label WarningTitleLabel = new System.Web.UI.WebControls.Label(); WarningTitleLabel.Font.Name = "Verdana"; WarningTitleLabel.Font.Size = 8; WarningTitleLabel.Font.Bold = true; WarningTitleLabel.ForeColor = System.Drawing.Color.Red; WarningTitleLabel.Text = " Warning: "; // Render the warning title WarningTitleLabel.RenderControl(writer); // Create a label with the description of the problem System.Web.UI.WebControls.Label WarningDescriptionLabel = new System.Web.UI.WebControls.Label(); WarningDescriptionLabel.Font.Name = "Verdana"; WarningDescriptionLabel.Font.Size = 8; WarningDescriptionLabel.Text = "This control requires that<br /> " + "a ScriptManager be on the Page"; // Render the warning description WarningDescriptionLabel.RenderControl(writer); } } else { base.RenderContents(writer); } } #endregion #region Child Control Event Handlers // Fires when the extent of the WebPart's Map Control changes private void Map_ExtentChanged(object sender, ESRI.ArcGIS.ADF.Web.UI.WebControls.ExtentEventArgs extentEventArgs) { // Make sure the event is not firing on map load (OldExtent == null) and the old and // new extents are distinct if (extentEventArgs.OldExtent != null && !extentEventArgs.OldExtent.Equals(extentEventArgs.NewExtent)) { try { // Get the data layer features in the new extent and update the graphics data // layer accordingly System.Data.DataTable queryResultsDataTable = GetDataLayerFeaturesInExtent(extentEventArgs.NewExtent); // If the total number of features in the data layer is greater than the max features property, // then we need to recreate the data graphics layer. Otherwise, the records in // queryResultsDataTable (which will be displayed on the WebPart's GridView) may include records // that are not in the graphics layer if ((m_adfMap.Page.Session["totalDataLayerFeatures"] != null) && ((int)m_adfMap.Page.Session["totalDataLayerFeatures"] > m_maxFeatures)) CreateGraphicsDataLayer(queryResultsDataTable); // Store the results table in session for use when the GridView is paging string resultsTableSessionKey = string.Format("{0}_queryResultsDataTable", this.ID); Page.Session[resultsTableSessionKey] = queryResultsDataTable; // Initialize the data source of the WebPart's GridView with the query results m_dataLayerGridView.DataSource = queryResultsDataTable; // Turn on paging m_dataLayerGridView.PageSize = 5; m_dataLayerGridView.AllowPaging = true; m_dataLayerGridView.PagerTemplate = null; // Bind the data source to the GridView m_dataLayerGridView.DataBind(); } catch (System.Exception ex) { System.Diagnostics.Debug.WriteLine(ex.Message); } } } // Adds interaction with the Map to each GridView row's mouseOver and click events private void GridView_RowDataBound(object sender, System.Web.UI.WebControls.GridViewRowEventArgs gridViewRowEventArgs) { // Make sure the row is a valid DataRow if (gridViewRowEventArgs.Row.RowType == System.Web.UI.WebControls.DataControlRowType.DataRow) { // Get the graphics resource from the map ESRI.ArcGIS.ADF.Web.DataSources.Graphics.MapFunctionality graphicsMapFunctionality = (ESRI.ArcGIS.ADF.Web.DataSources.Graphics.MapFunctionality)m_adfMap.GetFunctionality( m_graphicsMapResourceID); // Make sure the graphics resource contains a layer named "DataLayer." This is where // the feature graphics for the data layer features in the current extent are stored. if (graphicsMapFunctionality.GraphicsDataSet.Tables.Contains(m_graphicsDataLayerName)) { // Get the current row System.Web.UI.WebControls.GridViewRow gridViewRow = gridViewRowEventArgs.Row; // Get a reference to the DataLayer as a Web ADF GraphicsLayer ESRI.ArcGIS.ADF.Web.Display.Graphics.GraphicsLayer adfGraphicsLayer = graphicsMapFunctionality.GraphicsDataSet.Tables[m_graphicsDataLayerName] as ESRI.ArcGIS.ADF.Web.Display.Graphics.GraphicsLayer; // Get the client-side ID of the graphics layer string dataLayerID = m_adfMap.GetGraphicsLayerClientID(adfGraphicsLayer); // Find the index of the first unique ID column in the graphics layer's table int uniqueIDindex = -1; for (int i = 0; i < adfGraphicsLayer.Columns.Count; i++) { if (adfGraphicsLayer.Columns[i].Unique) { uniqueIDindex = i; break; } } // Get the index of the row in the graphics layer's table that has a unique ID // matching that of the current row System.Data.DataRowView dataRowView = gridViewRow.DataItem as System.Data.DataRowView; int graphicFeatureIndex = -1; for (int i = 0; i < adfGraphicsLayer.Rows.Count; i++) { if (adfGraphicsLayer.Rows[i][uniqueIDindex].Equals( dataRowView[uniqueIDindex])) { graphicFeatureIndex = i; break; } } // Create a JavaScript string that will (1) set the background color of the current // row, (2) get the graphicFeatureGroup (i.e. layer) for the DataLayer, (3) get // the graphicFeature corresponding to the current row index from the // graphicFeatureGroup, and (4) set the highlight on the graphicFeature string jsSetRowAndFeatureHighlight = "try {{" + "this.style.backgroundColor='{0}';" + "var graphicFeatureGroup = $find('{1}'); " + "var graphicFeature = graphicFeatureGroup.get({2}); " + "graphicFeature.set_highlight({3});" + "}} catch(ex) {{}}"; // 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, "yellow", dataLayerID, 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", dataLayerID, graphicFeatureIndex, "false")); // Uncomment the following code block to add a custom postback event that fires // when a row is clicked //// Get the JavaScript that will initiate a postback event with the parameters //// specified //string serverClick = this.Page.ClientScript.GetPostBackEventReference( // gridViewRow, "SelectClickedRow$" + gridViewRow.RowIndex); //// Add the postback JavaScript to the row's onclick event //gridViewRow.Attributes.Add("onclick", serverClick); // 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 envelope of the geometry, (5) get the WebPart's // client-side map object, and (6) zoom to the graphicFeature's envelope string jsZoomToFeature = string.Format("try {{" + "var graphicFeatureGroup = $find('{0}'); " + "var graphicFeature = graphicFeatureGroup.get({1}); " + "var geometry = graphicFeature.get_geometry();" + "var envelope = geometry.getEnvelope();" + "var map = $find('{2}');" + "map.zoomToBox(envelope, true);" + "}} catch(ex) {{}}", dataLayerID, graphicFeatureIndex, m_adfMap.ClientID); // Add the JavaScript to the current row's onclick event gridViewRow.Attributes.Add("onclick", jsZoomToFeature); } } } // Fires when the Page is changed in the GridView private void GridView_PageIndexChanging(object sender, System.Web.UI.WebControls.GridViewPageEventArgs gridViewPageEventArgs) { // Get a reference to the GridView System.Web.UI.WebControls.GridView gridView = sender as System.Web.UI.WebControls.GridView; // Get the page that is being paged to gridView.PageIndex = gridViewPageEventArgs.NewPageIndex; // Get the data table storing the features in the current extent from session string resultsTableSessionKey = string.Format("{0}_queryResultsDataTable", this.ID); System.Data.DataTable resultsDataTable = Page.Session[resultsTableSessionKey] as System.Data.DataTable; gridView.DataSource = resultsDataTable; gridView.DataBind(); } #endregion #region Child Control Initialization Methods // Creates and initializes a GridView for use in the WebPart private System.Web.UI.WebControls.GridView CreateGridView() { // Create the GridView and set dimensional/positional attributes System.Web.UI.WebControls.GridView gridView = new System.Web.UI.WebControls.GridView(); gridView = new System.Web.UI.WebControls.GridView(); gridView.ID = this.ID + "_gridView"; gridView.Width = new System.Web.UI.WebControls.Unit(350, System.Web.UI.WebControls.UnitType.Pixel); gridView.Style["position"] = "relative"; gridView.Style["top"] = "0px"; gridView.Style["left"] = "0px"; gridView.Style["width"] = "350px"; // Add an event handler for the GridView's RowDataBound event. This handler will add // functionality to each row's onmouseover and onclick events. gridView.RowDataBound += new System.Web.UI.WebControls.GridViewRowEventHandler( GridView_RowDataBound); gridView.DataBound += new System.EventHandler(GridView_DataBound); // Add an event handler for the GridView's PageIndexChanging event. This handler will // re-bind the GridView to the DataLayer's currently visible features so they are // displayed properly on the new page. gridView.PageIndexChanging += new System.Web.UI.WebControls.GridViewPageEventHandler(GridView_PageIndexChanging); return gridView; } void GridView_DataBound(object sender, System.EventArgs e) { m_gridViewDataBound = true; } // Adds map resources to the map resource manager private ESRI.ArcGIS.ADF.Web.UI.WebControls.MapResourceItem AddResourcesToMapResourceManager() { // Check whether a data source was specified by the user. Optionally, initialize with defaults. //if (string.IsNullOrEmpty(m_userDataSource)) //{ // m_mapResourceType = "ArcGIS Server Internet"; // m_userDataSource = "http://localhost/arcgis/services"; // m_mapResourceDefinition = "1@Layers@SanFrancisco"; // m_dataLayerName = "customers"; //} // Declare resource item variables ESRI.ArcGIS.ADF.Web.UI.WebControls.MapResourceItem mapResourceItem = null; ESRI.ArcGIS.ADF.Web.UI.WebControls.MapResourceItem backgroundResourceItem = null; // Make sure the map resource manager exists and that it does not contain any resource // items before initializing if (m_mapResourceManager != null && m_mapResourceManager.ResourceItems.Count == 0) { // Create the background resource item and initialize it to display the // ESRI_StreetMap_World_2D ArcGIS Online service ESRI.ArcGIS.ADF.Web.UI.WebControls.GISResourceItemDefinition gisBackgroundItemDefinition = Utility.CreateGISResourceItemDefinition("http://server.arcgisonline.com/v93", "ArcGIS Server Internet", string.Empty, "(default)@ESRI_StreetMap_World_2D", true); backgroundResourceItem = Utility.CreateResourceItem(m_backgroundMapResourceID, gisBackgroundItemDefinition); backgroundResourceItem.Parent = m_mapResourceManager; backgroundResourceItem.InitializeResource(); // Add the background resource item to the map resource manager Utility.AddMapResourceItemToResourceManager(m_mapResourceManager, false, backgroundResourceItem); // Create the resource item and initialize it to display the user-specified resource ESRI.ArcGIS.ADF.Web.UI.WebControls.GISResourceItemDefinition gisResourceItemDefinition = Utility.CreateGISResourceItemDefinition(m_userDataSource, m_dataSourceType, string.Empty, m_mapResourceDefinition, true); mapResourceItem = Utility.CreateResourceItem(m_dataLayerMapResourceID, gisResourceItemDefinition); mapResourceItem.Parent = m_mapResourceManager; mapResourceItem.InitializeResource(); // Add the user-specified resource item to the map resource manager Utility.AddMapResourceItemToResourceManager(m_mapResourceManager, true, mapResourceItem); // Create a graphics resource to display graphic features for the user-specified // data layer string graphicsDataSourceDefinition = "In Memory"; string graphicsDataSourceType = "GraphicsLayer"; ESRI.ArcGIS.ADF.Web.UI.WebControls.GISResourceItemDefinition graphicsResourceItemDefinition = Utility.CreateGISResourceItemDefinition(graphicsDataSourceDefinition, graphicsDataSourceType, "", "", true); ESRI.ArcGIS.ADF.Web.UI.WebControls.MapResourceItem graphicsResourceItem = Utility.CreateResourceItem(m_graphicsMapResourceID, graphicsResourceItemDefinition); graphicsResourceItem.Parent = m_mapResourceManager; graphicsResourceItem.InitializeResource(); // Add the graphics resource item to the map resource manager Utility.AddMapResourceItemToResourceManager(m_mapResourceManager, true, graphicsResourceItem); } else if (m_mapResourceManager.ResourceItems.Count > 0) { ESRI.ArcGIS.ADF.Web.UI.WebControls.GISResourceItemDefinition gisResourceItemDefinition = Utility.CreateGISResourceItemDefinition(m_userDataSource, m_dataSourceType, string.Empty, m_mapResourceDefinition, true); ESRI.ArcGIS.ADF.Web.UI.WebControls.MapResourceItem existingMapResourceItem = m_mapResourceManager.ResourceItems.Find(m_dataLayerMapResourceID); string existingResourceItemDefinition = existingMapResourceItem.Definition.ToString(); // Check to see if a new resource definition was provided by the user, if so, switch it out. if (existingResourceItemDefinition == gisResourceItemDefinition.ToString()) { return mapResourceItem; } m_mapResourceManager.ResourceItems.Remove(existingMapResourceItem); mapResourceItem = Utility.CreateResourceItem(m_dataLayerMapResourceID, gisResourceItemDefinition); mapResourceItem.Parent = m_mapResourceManager; mapResourceItem.InitializeResource(); // Add the user-specified resource item to the map resource manager m_mapResourceManager.ResourceItems.Insert(1, mapResourceItem); } return mapResourceItem; } // Initializes the map extent to the default extent of the passed-in map resource item private void InitializeMapExtent(ESRI.ArcGIS.ADF.Web.UI.WebControls.MapResourceItem mapResourceItem) { // Get the resource from the passed-in resource item ESRI.ArcGIS.ADF.Web.DataSources.IMapResource commonMapResource = mapResourceItem.Resource as ESRI.ArcGIS.ADF.Web.DataSources.IMapResource; if (commonMapResource != null) { try { // Get ArcGIS Server data source specific spatial references from the common // ADF spatial references of the passed-in resource and the WebPart's map ESRI.ArcGIS.ADF.ArcGISServer.SpatialReference agsResourceSpatialReference = ESRI.ArcGIS.ADF.Web.DataSources.ArcGISServer.Converter.FromAdfSpatialReference( commonMapResource.MapInformation.DefaultSpatialReference); ESRI.ArcGIS.ADF.ArcGISServer.SpatialReference agsMapSpatialReference = ESRI.ArcGIS.ADF.Web.DataSources.ArcGISServer.Converter.FromAdfSpatialReference( m_adfMap.SpatialReference); // Get an ArcGIS Server data-source specific envelope from the default extent of // the passed-in resource ESRI.ArcGIS.ADF.ArcGISServer.EnvelopeN agsResourceExtent = ESRI.ArcGIS.ADF.Web.DataSources.ArcGISServer.Converter.FromAdfEnvelope( commonMapResource.MapInformation.DefaultExtent); // Initialize an array of ArcGIS Server data-source specific geometries with // the converted resource extent ESRI.ArcGIS.ADF.ArcGISServer.Geometry[] agsInGeometryArray; agsInGeometryArray = new ESRI.ArcGIS.ADF.ArcGISServer.Geometry[1]; agsInGeometryArray[0] = agsResourceExtent; // Get a reference to the geometry service specified by the geometry service // URL property ESRI.ArcGIS.ADF.ArcGISServer.GeometryServerProxy geometryServer = new ESRI.ArcGIS.ADF.ArcGISServer.GeometryServerProxy(m_geometryServiceUrl); // Use the project method of the Geometry Service to project the extent of the // passed-in resource to the spatial reference of the map ESRI.ArcGIS.ADF.ArcGISServer.Geometry[] agsOutGeometryArray = geometryServer.Project( agsResourceSpatialReference, agsMapSpatialReference, false, null, null, agsInGeometryArray); // Get the projected extent from the output geometry array agsResourceExtent = agsOutGeometryArray[0] as ESRI.ArcGIS.ADF.ArcGISServer.EnvelopeN; // Convert the projected extent back to the ADF common envelope type and pass it to // the map's extent property m_adfMap.Extent = ESRI.ArcGIS.ADF.Web.DataSources.ArcGISServer.Converter.ToAdfEnvelope( agsResourceExtent); } catch { // Extent initialization failed, so initialize with a default extent m_adfMap.Extent = new ESRI.ArcGIS.ADF.Web.Geometry.Envelope(-122.42883176338381, 37.78331593769353, -122.41595716011233, 37.790826122935229); } } } #endregion #region Other Instance Methods // Method to set the color of the text of the selected row to red private void SelectRow(string controlEvent) { // Parse the control event string string[] controlEventArray = controlEvent.Split('$'); // Set the selected index of the GridView to the argument of the control event m_dataLayerGridView.SelectedIndex = System.Int32.Parse(controlEventArray[1]); // Set the text color of the selected row to red m_dataLayerGridView.SelectedRowStyle.ForeColor = System.Drawing.Color.Red; } // Determines whether a control of the passed-in type exists in the passed-in control collection private bool HasControlOfType(System.Type type, System.Web.UI.ControlCollection controlCollection) { // Iterate through all the controls in the passed-in control collection foreach (System.Web.UI.Control webControl in controlCollection) { // If the current control is of the passed-in type, return true. System.Type webControlType = webControl.GetType(); if (type.FullName == webControlType.FullName) return true; else if (webControl.HasControls()) { // The current control has child controls, so call this function on // those child controls bool hasControlOfType = HasControlOfType(type, webControl.Controls); if (hasControlOfType) return true; } } // If the code reaches this point, no match was found. return false; } // Updates the WebPart instance's graphics data layer to display the passed-in table private void CreateGraphicsDataLayer(System.Data.DataTable dataTable) { // Get the functionality for the graphics resource ESRI.ArcGIS.ADF.Web.DataSources.Graphics.MapFunctionality graphicsMapFunctionality = (ESRI.ArcGIS.ADF.Web.DataSources.Graphics.MapFunctionality)m_adfMap.GetFunctionality( m_graphicsMapResourceID); // Get a reference to the passed-in data table as a feature graphics layer by using the // Web ADF's convenience method ESRI.ArcGIS.ADF.Web.Display.Graphics.FeatureGraphicsLayer featureGraphicsLayer = (ESRI.ArcGIS.ADF.Web.Display.Graphics.FeatureGraphicsLayer) ESRI.ArcGIS.ADF.Web.Converter.ToGraphicsLayer(dataTable, System.Drawing.Color.Blue, System.Drawing.Color.Yellow, System.Drawing.Color.Red, true); if (featureGraphicsLayer.FeatureType == ESRI.ArcGIS.ADF.Web.FeatureType.Point) { string urlRedIcon = Page.ClientScript.GetWebResourceUrl(GetType(), "ADFWebPart.images.sphere-red-16x16.png"); ESRI.ArcGIS.ADF.Web.Display.Symbol.RasterMarkerSymbol defaultSymbol = new ESRI.ArcGIS.ADF.Web.Display.Symbol.RasterMarkerSymbol(urlRedIcon); defaultSymbol.XOffset = 0; defaultSymbol.YOffset = 8; defaultSymbol.Height = 16; defaultSymbol.Width = 16; ESRI.ArcGIS.ADF.Web.Display.Renderer.SimpleRenderer defaultRenderer = new ESRI.ArcGIS.ADF.Web.Display.Renderer.SimpleRenderer(defaultSymbol); featureGraphicsLayer.Renderer = defaultRenderer; string urlYellowIcon = Page.ClientScript.GetWebResourceUrl(GetType(), "ADFWebPart.images.sphere-yellow-16x16.png"); ESRI.ArcGIS.ADF.Web.Display.Symbol.RasterMarkerSymbol highlightSymbol = new ESRI.ArcGIS.ADF.Web.Display.Symbol.RasterMarkerSymbol(urlYellowIcon); highlightSymbol.XOffset = 0; highlightSymbol.YOffset = 8; highlightSymbol.Height = 16; highlightSymbol.Width = 16; ESRI.ArcGIS.ADF.Web.Display.Renderer.SimpleRenderer highlightRenderer = new ESRI.ArcGIS.ADF.Web.Display.Renderer.SimpleRenderer(highlightSymbol); featureGraphicsLayer.HighlightRenderer = highlightRenderer; } // Set the name of the graphics layer featureGraphicsLayer.TableName = m_graphicsDataLayerName; // Specify that the graphics layer should be drawn on the client, meaning mapTips will be // displayed featureGraphicsLayer.RenderOnClient = true; // If the graphics resource already contains a table with the graphics data layer name, // remove it if (graphicsMapFunctionality.GraphicsDataSet.Tables.Contains(featureGraphicsLayer.TableName)) graphicsMapFunctionality.GraphicsDataSet.Tables.Remove(featureGraphicsLayer.TableName); // Retrieve the layer ID of the user-specified data layer from the dynamically created map resource ESRI.ArcGIS.ADF.Web.DataSources.IMapFunctionality commonMapFunctionality = m_adfMap.GetFunctionality(m_dataLayerMapResourceID); string[] layerIDs = null; string[] layerNames = null; string dataLayerID = null; commonMapFunctionality.GetLayers(out layerIDs, out layerNames); for (int i = 0; i < layerIDs.Length; i++) { if (layerNames[i] == m_dataLayerName) { dataLayerID = layerIDs[i]; break; } } // Get the LayerFormat of the data layer, which specifies the format of the callouts that appear // when hovering over features ESRI.ArcGIS.ADF.Web.UI.WebControls.LayerFormat layerFormat = ESRI.ArcGIS.ADF.Web.UI.WebControls.LayerFormat.FromMapResourceManager(m_mapResourceManager, m_dataLayerMapResourceID, dataLayerID); // Loop through the LayerFormat's fields collection, copying the aliases specfied from the WebPart's // GridView and hiding fields that are not in the GridView for (int i = 0; i < layerFormat.Fields.Count; i++) { bool fieldDisplayed = false; for (int j = 0; j < m_dataLayerGridView.Columns.Count; j++) { System.Web.UI.WebControls.BoundField boundField = (System.Web.UI.WebControls.BoundField)m_dataLayerGridView.Columns[j]; if (boundField.DataField == layerFormat.Fields[i].Name) { layerFormat.Fields[i].Alias = boundField.HeaderText; layerFormat.Fields[i].Visible = true; fieldDisplayed = true; break; } if (!fieldDisplayed) layerFormat.Fields[i].Visible = false; } } // Since we want to preserve the colors specified when creating the graphics layer via the Web ADF Converter // method, we have to explicitly retrieve the renderers from the graphics layer before applying the LayerFormat. // Otherwise, the symbology contained in these renderers will be overwritten with whatever the LayerFormat // of the data layer specifies. // Transfer the selected and highlight renderers from the graphics layer to the layer format directly. // While the Renderer property of a layer format defines the default renderer for GraphicFeatures on the client, // each row in the Web-tier graphics layer must be selected (the IS_SELECTED field must be true) to be rendered on the client. // If the graphics layer was rendered on the Web-tier, the selected renderer would be used. // Since a layer format does not maintain a "SelectedRenderer" property a reference to the selected rendered is stored // before the layer format is applied to the graphics layer, then reset. ESRI.ArcGIS.ADF.Web.Display.Renderer.IRenderer selectedRenderer = featureGraphicsLayer.SelectedRenderer; layerFormat.Renderer = featureGraphicsLayer.Renderer; layerFormat.HighlightRenderer = featureGraphicsLayer.HighlightRenderer; featureGraphicsLayer.SelectedRenderer = selectedRenderer; // Apply the layer format layerFormat.Apply(featureGraphicsLayer); // Add the layer to the graphics resource graphicsMapFunctionality.GraphicsDataSet.Tables.Add(featureGraphicsLayer); //featureGraphicsLayer.ForceFullClientGraphicsRefresh = true; m_adfMap.RefreshResource(m_graphicsMapResourceID); } // Queries the user-specified resource for features that are in the passed-in extent private System.Data.DataTable GetDataLayerFeaturesInExtent(ESRI.ArcGIS.ADF.Web.Geometry.Envelope adfExtent) { // Get a reference to the functionality of the user-specified resource ESRI.ArcGIS.ADF.Web.DataSources.IMapFunctionality commonMapFunctionality = (ESRI.ArcGIS.ADF.Web.DataSources.IMapFunctionality)m_adfMap.GetFunctionality(m_dataLayerMapResourceID); // Get a reference to the user-specified resource 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 queryFunctionality = (ESRI.ArcGIS.ADF.Web.DataSources.IQueryFunctionality)gisResource.CreateFunctionality (typeof(ESRI.ArcGIS.ADF.Web.DataSources.IQueryFunctionality), null); // Get the resource's queryable layers string[] layerIDs; string[] layerNames; queryFunctionality.GetQueryableLayers(null, out layerIDs, out layerNames); // Get the layerID of the user-specified data layer string dataLayerID = null; for (int index = 0; index < layerNames.Length; index++) { if (layerNames[index] == m_dataLayerName) { dataLayerID = layerIDs[index]; break; } } // Initialze a spatial filter with the passed-in extent ESRI.ArcGIS.ADF.Web.SpatialFilter spatialFilter = new ESRI.ArcGIS.ADF.Web.SpatialFilter(); spatialFilter.ReturnADFGeometries = true; spatialFilter.MaxRecords = m_maxFeatures; spatialFilter.Geometry = adfExtent; // Query the data layer with the passed-in extent and return the results System.Data.DataTable resultDataTable = queryFunctionality.Query( commonMapFunctionality.Name, dataLayerID, spatialFilter); return resultDataTable; } private bool propertyCheck() { if (!string.IsNullOrEmpty(m_userDataSource) && !string.IsNullOrEmpty(m_dataSourceType) && !string.IsNullOrEmpty(m_mapResourceDefinition) && !string.IsNullOrEmpty(m_dataLayerName) && m_hasScriptManager) { return true; } return false; } #endregion #region Instance Properties /// <summary> /// ArcGIS Server resource type. Valid values are "ArcGIS Server Local" and /// "ArcGIS Server Internet" /// </summary> [System.Web.UI.WebControls.WebParts.Personalizable( System.Web.UI.WebControls.WebParts.PersonalizationScope.Shared), System.Web.UI.WebControls.WebParts.WebBrowsable(true), System.ComponentModel.Category("Resources"), System.Web.UI.WebControls.WebParts.WebDescription("Valid values are 'ArcGIS Server Local' and 'ArcGIS Server Internet'"), System.Web.UI.WebControls.WebParts.WebDisplayName("ArcGIS Server Data Source Type")] public string DataSourceType { get { return m_dataSourceType; } set { m_dataSourceType = value; } } /// <summary> /// Machine name or URL of the ArcGIS Server services host /// </summary> [System.Web.UI.WebControls.WebParts.Personalizable( System.Web.UI.WebControls.WebParts.PersonalizationScope.Shared), System.Web.UI.WebControls.WebParts.WebBrowsable(true), System.ComponentModel.Category("Resources"), System.Web.UI.WebControls.WebParts.WebDescription("ArcGIS Server machine name or Url"), System.Web.UI.WebControls.WebParts.WebDisplayName("ArcGIS Server Data Source")] public string DataSource { get { return m_userDataSource; } set { m_userDataSource = value; } } /// <summary> /// ArcGIS Server Resource. Must be formatted as <DataFrameName>@<ServiceName> /// </summary> [System.Web.UI.WebControls.WebParts.Personalizable( System.Web.UI.WebControls.WebParts.PersonalizationScope.Shared), System.Web.UI.WebControls.WebParts.WebBrowsable(true), System.ComponentModel.Category("Resources"), System.Web.UI.WebControls.WebParts.WebDescription("Format to use is DataFrameName@ServiceName"), System.Web.UI.WebControls.WebParts.WebDisplayName("ArcGIS Server Resource String")] public string ResourceDefinition { get { return m_mapResourceDefinition; } set { m_mapResourceDefinition = value; } } /// <summary> /// Name of the layer for which data will be displayed in the GridView /// </summary> [System.Web.UI.WebControls.WebParts.Personalizable( System.Web.UI.WebControls.WebParts.PersonalizationScope.Shared), System.Web.UI.WebControls.WebParts.WebBrowsable(true), System.ComponentModel.Category("Resources"), System.Web.UI.WebControls.WebParts.WebDescription("Name of layer to display features in map and table"), System.Web.UI.WebControls.WebParts.WebDisplayName("Data display layer name")] public string DataLayerName { get { return m_dataLayerName; } set { m_dataLayerName = value; m_graphicsDataLayerName = m_dataLayerName + "_Graphics"; } } /// <summary> /// NameValueCollection of fields to display on the WebPart's GridView and when hovering over the /// data layer's graphic features. Each name in the collection specifies a database field name, /// while each value is the alias to display for that field. /// </summary> [System.Web.UI.WebControls.WebParts.Personalizable( System.Web.UI.WebControls.WebParts.PersonalizationScope.Shared), System.Web.UI.WebControls.WebParts.WebBrowsable(true), System.ComponentModel.Category("Resources"), System.Web.UI.WebControls.WebParts.WebDescription("Collection of fields to display"), System.Web.UI.WebControls.WebParts.WebDisplayName("Collection of fields to display")] public System.Collections.Specialized.NameValueCollection DisplayFields { get { return m_fieldsCollection; } set { m_fieldsCollection = value; } } /// <summary> /// NameValueCollection of fields to display on the WebPart's GridView and when hovering over the /// data layer's graphic features. Each name in the collection specifies a database field name, /// while each value is the alias to display for that field. /// </summary> [System.Web.UI.WebControls.WebParts.Personalizable( System.Web.UI.WebControls.WebParts.PersonalizationScope.Shared), System.Web.UI.WebControls.WebParts.WebBrowsable(true), System.ComponentModel.Category("Resources"), System.Web.UI.WebControls.WebParts.WebDescription("Comma delimited field-alias relationships, semi-colon delimited field-alias groups."), System.Web.UI.WebControls.WebParts.WebDisplayName("Collection of fields, aliases to display")] public string DisplayFieldsString { get { System.Text.StringBuilder sb = new System.Text.StringBuilder(); if (m_fieldsCollection != null) { for (int n = 0; n < m_fieldsCollection.Count; n++) { sb.Append(m_fieldsCollection.GetKey(n) + "," + m_fieldsCollection.GetValues(n)[0]); if (n != m_fieldsCollection.Count - 1) { sb.Append(";"); } } } return sb.ToString(); } set { System.Collections.Specialized.NameValueCollection fieldsCollection = new System.Collections.Specialized.NameValueCollection(); if (!string.IsNullOrEmpty(value)) { string[] fieldAliasPairs = value.Split(";".ToCharArray()); for (int f = 0; f < fieldAliasPairs.Length; f++) { string[] fieldAlias = fieldAliasPairs[f].Split(",".ToCharArray()); fieldsCollection.Add(fieldAlias[0], fieldAlias[1]); } m_fieldsCollection = fieldsCollection; } } } /// <summary> /// Maximum number of data layer features that can be displayed in the WebPart's /// graphics layer and GridView. /// </summary> [System.Web.UI.WebControls.WebParts.Personalizable( System.Web.UI.WebControls.WebParts.PersonalizationScope.Shared), System.Web.UI.WebControls.WebParts.WebBrowsable(true), System.ComponentModel.Category("Resources"), System.Web.UI.WebControls.WebParts.WebDescription("Maximum number of records to display"), System.Web.UI.WebControls.WebParts.WebDisplayName("Maximum number of records to display")] public int MaxDataLayerFeatures { get { return m_maxFeatures; } set { m_maxFeatures = value; } } /// <summary> /// Url of the geometry service used to manage projections /// </summary> [System.Web.UI.WebControls.WebParts.Personalizable( System.Web.UI.WebControls.WebParts.PersonalizationScope.Shared), System.Web.UI.WebControls.WebParts.WebBrowsable(true), System.ComponentModel.Category("Resources"), System.Web.UI.WebControls.WebParts.WebDescription("ArcGIS Server Geometry Service URL"), System.Web.UI.WebControls.WebParts.WebDisplayName("ArcGIS Server Geometry Service URL")] public string GeometryServiceUrl { get { return m_geometryServiceUrl; } set { m_geometryServiceUrl = value; } } #endregion } }