Common_PostbackManager_VBNet\PostbackManagerWebSite\GetAttributeTable.aspx.vb
' 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. ' Imports Microsoft.VisualBasic Imports System Public Partial Class GetAttributeTable Inherits System.Web.UI.Page #Region "Page Member Variables" ' Whether attributes are to be retrieved for the clicked layer Private _getLayerAttributes As Boolean = False ' The number of records displayed at one time on the attribute table Private _pageSize As Integer = 20 #End Region #Region "ASP.NET Page Life Cycle Event Handlers - Page_Load" ' Wires event handlers Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) AddHandler PostbackManager1.RequestReceived, AddressOf PostbackManager1_RequestReceived AddHandler Toc1.NodeClicked, AddressOf Toc1_NodeClicked AddHandler Toc1.NodesPopulated, AddressOf Toc1_NodesPopulated End Sub #End Region #Region "Web ADF Control Event Handlers - Toc1_NodesPopulated, Toc1_NodeClicked" ' Fires once the TOC's nodes have been initialized Private Sub Toc1_NodesPopulated(ByVal sender As Object, ByVal e As System.EventArgs) ' Find which nodes correspond to a layer and mark them with an HTML attribute For Each node As ESRI.ArcGIS.ADF.Web.UI.WebControls.TreeViewPlusNode In Toc1.Nodes Me.MarkLayerNodes(node) Next node End Sub ' Fires when a TOC node is clicked Private Sub Toc1_NodeClicked(ByVal sender As Object, ByVal args As ESRI.ArcGIS.ADF.Web.UI.WebControls.TreeViewPlusNodeEventArgs) ' Check whether layer attributes are to be retrieved. This value is set in ' PostbackManager1_RequestReceived If (Not _getLayerAttributes) Then Return End If ' Get the TocLayer corresponding to the clicked node Dim selectedLayer As ESRI.ArcGIS.ADF.Web.TocLayer = TryCast(args.Node.Data, ESRI.ArcGIS.ADF.Web.TocLayer) ' Get the data frame node that contains the layer node Dim dataFrameNode As ESRI.ArcGIS.ADF.Web.UI.WebControls.TreeViewPlusNode = Me.GetParentDataFrameNode(args.Node) ' Create a data table containing the clicked layer's attributes Dim attributeTable As System.Data.DataTable = Me.GetLayerAttributeData(Map1, dataFrameNode.Text, selectedLayer.ID) ' Apply the layer's LayerFormat to the attribute table. This will set properties such as field ' visibilities and display names. Dim layerFormat As ESRI.ArcGIS.ADF.Web.UI.WebControls.LayerFormat = ESRI.ArcGIS.ADF.Web.UI.WebControls.LayerFormat.FromMapResourceManager(MapResourceManager1, dataFrameNode.Text, selectedLayer.ID) layerFormat.Apply(attributeTable) ' Store the table in session for quick retrieval during paging or sorting Me.Session("AttributeTable") = attributeTable ' Calculate the number of pages the displayed table will have and store the number in session Dim pageCount As Integer = CInt(Fix(System.Math.Round((CDbl(attributeTable.Rows.Count) / CDbl(_pageSize)) +.5))) Me.Session("PageCount") = pageCount ' Display the table's first page Me.ShowAttributeTable(1) ' Copy the callback results of the floating panel containing the table to the TOC so the ' results that will display the table are processed on the client. Toc1.CallbackResults.CopyFrom(FloatingPanel1.CallbackResults) ' Pass the name of the clicked layer back to the client via PostbackManager's CustomResults property. ' This will be used to update the floating panel's title. PostbackManager1.CustomResults = args.Node.Text End Sub #End Region #Region "Custom Control Event Handlers - PostbackManager1_RequestReceived" Private Sub PostbackManager1_RequestReceived(ByVal sender As Object, ByVal args As PostbackManager_VBNet.AdfRequestEventArgs) ' Get the request's arguments and extract EventArg Dim requestArgs As System.Collections.Specialized.NameValueCollection = ESRI.ArcGIS.ADF.Web.UI.WebControls.Utility.ParseStringIntoNameValueCollection(args.RequestArguments, True) Dim eventArg As String = requestArgs("EventArg") ' Check whether the request was initiated by the TOC If args.CallingControl.ID = Toc1.ID Then ' Check whether the request includes the custom argument indicating that layer attributes are to be ' retrieved. This argument is added to the request on the client via onAdfRequest, which is a handler for ' the PostbackManager's client-side invokingRequest event. If Not requestArgs("getAttributes") Is Nothing Then _getLayerAttributes = True End If ' Check whether the request was initiated by paging or sorting the attribute table ElseIf eventArg = "nextPage" OrElse eventArg="previousPage" OrElse eventArg="firstPage" OrElse eventArg="lastPage" OrElse eventArg="sort" Then ' Get the current page number Dim pageNumber As Integer = CInt(Fix(Me.Session("PageNumber"))) Select Case eventArg ' Set the page number if the request is for paging. If it is for sorting, call the SortAttributeTable method Case "nextPage" pageNumber += 1 Case "previousPage" pageNumber -= 1 Case "firstPage" pageNumber = 1 Case "lastPage" pageNumber = CInt(Fix(Me.Session("PageCount"))) Case "sort" Me.SortAttributeTable(requestArgs("Column")) End Select ' Update the displayed table to show the specified page Me.ShowAttributeTable(pageNumber) ' Copy the callback results of the floating panel containing the attribute table to the PostbackManager so the ' updates to the table display are processed on the client. PostbackManager1.CallbackResults.CopyFrom(FloatingPanel1.CallbackResults) End If End Sub #End Region #Region "Private Page Methods" #Region "TOC Node Manipulation - MarkLayerNodes, GetParentDataFrameNode" ' Finds TOC layer nodes that are descendants of the passed-in node and adds an HTML attribute to ' them marking them as such Private Sub MarkLayerNodes(ByVal node As ESRI.ArcGIS.ADF.Web.UI.WebControls.TreeViewPlusNode) ' Check whether the passed-in node is a layer node and add an "IsLayer" attribute to it if so If TypeOf node.Data Is ESRI.ArcGIS.ADF.Web.TocLayer Then node.Attributes.Add("IsLayer", "true") End If ' Recursively call the method on the passed-in node's child nodes For Each childNode As ESRI.ArcGIS.ADF.Web.UI.WebControls.TreeViewPlusNode In node.Nodes Me.MarkLayerNodes(childNode) Next childNode End Sub ' Retrieves the TOC data frame node that is an ancestor of the passed-in node Private Function GetParentDataFrameNode(ByVal node As ESRI.ArcGIS.ADF.Web.UI.WebControls.TreeViewPlusNode) As ESRI.ArcGIS.ADF.Web.UI.WebControls.TreeViewPlusNode ' Declare a node variable to hold the function's return value Dim dataFrameNode As ESRI.ArcGIS.ADF.Web.UI.WebControls.TreeViewPlusNode = Nothing ' If the current node is a data frame node, store it in the return variable. Otherwise, call the ' method recursively on the node's parent. If TypeOf node.Data Is ESRI.ArcGIS.ADF.Web.TocDataFrame Then dataFrameNode = node Else dataFrameNode = Me.GetParentDataFrameNode(TryCast(node.Parent, ESRI.ArcGIS.ADF.Web.UI.WebControls.TreeViewPlusNode)) End If Return dataFrameNode End Function #End Region #Region "Attribute Table Manipulation - ShowAttributeTable, PopulateAttributeTable, SortAttributeTable" ' Updates the AttributeTable control to display attributes on the specified page of the current layer Private Sub ShowAttributeTable(ByVal pageNumber As Integer) ' Retrieve the number of attribute pages and validate the requested page number Dim pageCount As Integer = CInt(Fix(Me.Session("PageCount"))) If pageNumber = 0 OrElse pageNumber > pageCount Then Return End If ' Update the current page number Me.Session("PageNumber") = pageNumber ' Get the attribute DataTable for the current layer Dim attributeTable As System.Data.DataTable = TryCast(Me.Session("AttributeTable"), System.Data.DataTable) ' Calculate the first and last indexes of the rows to be displayed Dim startIndex As Integer = (pageNumber - 1) * _pageSize Dim stopIndex As Integer = (pageNumber * _pageSize) - 1 If stopIndex >= attributeTable.Rows.Count Then stopIndex = attributeTable.Rows.Count - 1 End If ' Update the attribute table display Me.PopulateAttributeTable(attributeTable, startIndex, stopIndex) ' Update the paging text PageLabel.Text = String.Format("Current Page: {0} of {1}", pageNumber, pageCount) ' Make sure the floating panel containing the attribute table is visible, then refresh it to ' apply the updates to the attribute table control FloatingPanel1.ShowFloatingPanel() FloatingPanel1.Refresh() End Sub ' Displays the data specified by the method parameters on the AttributeTable control Private Sub PopulateAttributeTable(ByVal dataTable As System.Data.DataTable, ByVal startIndex As Integer, ByVal stopIndex As Integer) ' Remove all rows from the display table AttributeTable.Rows.Clear() AttributeTable.GridLines = System.Web.UI.WebControls.GridLines.Both ' Create a row for the header row and add it to the display table Dim row As System.Web.UI.WebControls.TableRow = New System.Web.UI.WebControls.TableRow() AttributeTable.Rows.Add(row) Dim cell As System.Web.UI.WebControls.TableCell = Nothing ' Add the name of each visible field to the header row For Each column As System.Data.DataColumn In dataTable.Columns ' Check whether the current column is visible If System.Convert.ToBoolean(column.ExtendedProperties(ESRI.ArcGIS.ADF.Web.Constants.ADFVisibility)) Then ' Create a cell for the column header and apply a bold font to it cell = New System.Web.UI.WebControls.TableCell() cell.Font.Bold = True ' Set the header text to either the field's display name or its database name if a display name is ' not specified Dim headerText As String If (String.IsNullOrEmpty(column.Caption)) Then headerText = column.ColumnName Else headerText = column.Caption End If ' Create a hyperlink for the header - we do this to make the table sortable by clicking a header cell Dim sortLink As System.Web.UI.HtmlControls.HtmlAnchor = New System.Web.UI.HtmlControls.HtmlAnchor() sortLink.InnerText = headerText ' Set the header link to issue an asynchronous request to the server via PostbackManager's doAsyncRequest sortLink.HRef = String.Format("javascript:ESRI.ADF.Samples.PostbackManager.doAsyncRequest('EventArg=sort&Column={0}');", headerText) cell.Controls.Add(sortLink) row.Cells.Add(cell) End If Next column ' Add the data rows to the display table Dim i As Integer = startIndex Do While i <= stopIndex ' Add a row to the display table row = New System.Web.UI.WebControls.TableRow() AttributeTable.Rows.Add(row) ' Get the current row from the data table Dim dataRow As System.Data.DataRow = dataTable.Rows(i) ' Add a new cell for each visible column and populate it with that column's value For Each column As System.Data.DataColumn In dataTable.Columns ' Check whether the current field is visible If System.Convert.ToBoolean(column.ExtendedProperties(ESRI.ArcGIS.ADF.Web.Constants.ADFVisibility)) Then ' Set the cell's text to be the value of the current column in the current row cell = New System.Web.UI.WebControls.TableCell() cell.Text = System.Convert.ToString(dataRow(column.ColumnName)).Trim() ' Set a tab as the cell's text if there is no current value. Without this, the cell borders do ' not render in this situation. If String.IsNullOrEmpty(cell.Text) Then cell.Text = " " End If row.Cells.Add(cell) End If Next column i += 1 Loop End Sub ' Sorts the display table on the specified column Private Sub SortAttributeTable(ByVal columnName As String) ' Get the current data table from session Dim attributeTable As System.Data.DataTable = TryCast(Me.Session("AttributeTable"), System.Data.DataTable) ' If the column has a display name specified, retrieve the database field name If (Not attributeTable.Columns.Contains(columnName)) Then For Each column As System.Data.DataColumn In attributeTable.Columns If column.Caption = columnName Then columnName = column.ColumnName Exit For End If Next column End If ' Get the current sort direction Dim currentSort As String = TryCast(Me.Session("CurrentSort"), String) ' Create a sort expression that will sort on the passed-in column in the opposite ' direction of the current sort Dim sortExpression As String If (currentSort = String.Format("{0} ASC", columnName)) Then sortExpression = String.Format("{0} DESC", columnName) Else sortExpression = String.Format("{0} ASC", columnName) End If ' Update the current sort expression stored in session Me.Session("CurrentSort") = sortExpression ' Apply the sort attributeTable.DefaultView.Sort = sortExpression ' Replace the current data table with the sorted table Me.Session("AttributeTable") = attributeTable.DefaultView.ToTable() End Sub #End Region ' Retrieves attribute data for the specified layer Private Function GetLayerAttributeData(ByVal adfMap As ESRI.ArcGIS.ADF.Web.UI.WebControls.Map, ByVal resourceName As String, ByVal layerID As String) As System.Data.DataTable ' Get the map functionality for the resource Dim mapFunctionality As ESRI.ArcGIS.ADF.Web.DataSources.IMapFunctionality = adfMap.GetFunctionality(resourceName) ' Get the resource and make sure it supports querying Dim gisResource As ESRI.ArcGIS.ADF.Web.DataSources.IGISResource = mapFunctionality.Resource Dim supportsQueries As Boolean = gisResource.SupportsFunctionality (GetType(ESRI.ArcGIS.ADF.Web.DataSources.IQueryFunctionality)) If (Not supportsQueries) Then Return Nothing End If ' Get query functionality for the resource Dim queryFunctionality As ESRI.ArcGIS.ADF.Web.DataSources.IQueryFunctionality = TryCast(gisResource.CreateFunctionality(GetType(ESRI.ArcGIS.ADF.Web.DataSources.IQueryFunctionality), Nothing), ESRI.ArcGIS.ADF.Web.DataSources.IQueryFunctionality) ' Initialize a query filter. We do not specify a where clause so all features are returned. ' We also specify that geometry not be returned since only the attribute data will be used and ' retrieving geometry is a relatively expensive operation. Dim adfQueryFilter As ESRI.ArcGIS.ADF.Web.QueryFilter = New ESRI.ArcGIS.ADF.Web.QueryFilter() adfQueryFilter.ReturnADFGeometries = False adfQueryFilter.MaxRecords = 10000 ' Execute the query, returning the result Return queryFunctionality.Query(mapFunctionality.Name, layerID, adfQueryFilter) End Function #End Region End Class