Professional ASP.NET 1.0 Special Edition- P12

Chia sẻ: Cong Thanh | Ngày: | Loại File: PDF | Số trang:40

lượt xem

Professional ASP.NET 1.0 Special Edition- P12

Mô tả tài liệu
  Download Vui lòng tải xuống để xem tài liệu đầy đủ

Professional ASP.NET 1.0 Special Edition- P12:Those of us who are Microsoft developers can't help but notice that .NET has received a fair amount of visibility over the last year or so. This is quite surprising considering that for most of this period, .NET has been in its early infancy and beta versions. I can't remember any unreleased product that has caused this much interest among developers. And that's really an important point, because ignoring all the hype and press, .NET really is a product for developers, providing a great foundation for building all types of applications....

Chủ đề:

Nội dung Text: Professional ASP.NET 1.0 Special Edition- P12

  1. 'Release Date' Column: Visible   Hidden Next comes the DataGrid control definition. It's on our because it contains controls that we want to use to post the page back to our server (that is, the More Info buttons). It uses the techniques we've just been discussing to create a custom column layout (including columns that contain only a non-breaking space and are simply there to give the required appearance for the control):
  3. The penultimate ASP:TemplateColumn control contains an element that specifies that each row will contain an ASP:Button control with the caption More Info. It also specifies that the CommandName property of the button is "Info". We'll see how we use this when we look at the code in the page shortly. The only other control is the Label named lblInfo that we use to display information about each book in the table: Binding the DataGrid The code in this page is divided into three subroutines: Page_Load is executed each time the page is loaded. It sets the visibility of the Released column and then calls the BindDataGrid routine. BindDataGrid fetches the data from the database and returns it as a DataReader object. Then it binds this to the DataGrid control to display the values. ShowInfo runs when any of the command buttons in the grid is clicked. It retrieves the ISBN and title of the book from the row and displays it in the Label control at the foot of the page. Showing and Hiding Columns When we click the relevant radio button at the top of the page, the Released column is hidden or shown in the grid. Compare this next screenshot with the previous one to see the difference:
  4. The radio buttons have their AutoPostback property set to True so that the page is reloaded each time the selection is changed. In the Page_Load event, we check to see if this is the first time the page has been loaded. If not (that is, if it's a postback) we just set the Visible property of the appropriate column using its index within the Columns collection of the DataGrid control. If it's not a postback, we have to set the default value for the radio buttons and bind the grid to the data source. In this case, the Released column will be displayed, because the default is to show all columns: Sub Page_Load() If Page.IsPostBack Then 'display or hide the "Released" column 'have to use the index of the column not the column name MyDataGrid.Columns(3).Visible = (chkVisible.Checked = True) Else chkVisible.Checked = True 'set default value
  5. BindDataGrid() 'create dataset and bind grid End If End Sub Reacting to the ItemCommand Event The other interesting feature of the example page is how it displays information about each book in response to a click on the More Info button. In the definition of the DataGrid control, we specified the name of an event handler for the ItemCommand event by setting the OnItemCommand property of the DataGrid: OnItemCommand="ShowInfo" When any control within the grid is activated - in our case the ASP:Button control with the caption More Info - this event handler is executed. The parameters sent to the event handler contain a reference to the control that initiated the event, and a DataGridCommandEventArgs object that contains details of the event as well as references to the current row in the control (the row containing the control that was activated). Within our event handler, we access the CommandName of the CommandSource object (our More Info button) to see which control it was that activated the event (there could be more than one in each row). Our button has a CommandName property value of Info, so we can choose the action to take based on this: Sub ShowInfo(objSender As Object, objArgs As DataGridCommandEventArgs) 'runs when any command button in the grid is clicked 'see if the CommandName of the clicked button was "Info" If objArgs.CommandSource.CommandName = "Info" Then ... Now we've identified that it was the More Info button that was clicked, we can access the values in that particular row of our control. The DataGridCommandEventArgs object (here named objArgs) exposes the items in the current row of a DataGrid control as a Cells collection. We access the cell we want by specifying its index within the row (starting at
  6. zero), and get the value from the Text property. Then we can use these values to create the output and place it in the Label control located below the grid on our page: ... 'get values of ISBN and Title from Text property of the table cells 'for the current row returned in the objArgs parameter values Dim strISBN As String = objArgs.Item.Cells(1).Text Dim strTitle As String = objArgs.Item.Cells(2).Text 'display the information in the page- possibly extract from database? lblInfo.Text = "More information about the book:" & strTitle _ & "(ISBN " &strISBN & ") goes here..." End If End Sub Using this technique we could extract the ISBN and use it to look up information about the book in another table. Or we could even use it to access another web site or a Web Service to get information to display to the user. Handling Data Binding Events The content of each cell or item in a list control is created as that control is being executed, as part of the overall page creation process. This means that the content of each cell is controlled only by the value in the data source and the formatting applied by the template or style properties in the control definition. However, it's often useful to be able to access and modify the content at runtime, based on the actual value that occurs in the source dataset. We can do this by reacting to events that the control raises. The most useful in this scenario is the DataBinding event, which occurs after the values for the column have been determined, but before they are output to the client. This event is supported in all the list controls designed for data binding, including the ASP:DataGrid, ASP:DataList, ASP:Repeater, and HtmlSelect controls. In essence we just have to create a handler for the event, and tell the control where to find this event handler. It is then
  7. called for each row in the data source as the binding takes place. Within the event handler, we can access the entire row of data, and modify the content of any of the controls within that row. The example page Handling Data Binding Events in a DataList Object (datalist-bind-events.aspx) demonstrates this technique by adding the slogan "Great for ASP Programmers!" to any book title that contains the words "Active Server Pages" or "ADO": How It Works The definition of the DataList control we use in this example is much the same as in previous examples. We have , , and elements along with some CSS styles to specify how to format the output from the control. What's important here is that we also set the OnItemDataBound property of the DataList object to the name of an event handler that we want to be executed as each row in the list is bound to the data source: ...
  8. We use the same Page_Load event handler as in previous examples to get a DataView object that contains our source data from the separate custom user control, and bind it to the grid for display. What makes this example different is the event handler that we have specified for the ItemDataBound event. Reacting to the ItemDataBound Event Our event handler, named CheckTitle, is shown next. When it's called by the control, as each row is bound to the source data, it is passed two parameters. The first is the usual reference to the object that caused the event, and the second is a DataListItemEventArgs object that contains information about the event, and the row that was being bound. The first thing we do in our event handler is to check what type of row was being bound - whether it's a header row, footer row, item row, alternating item row, and so on (the type of template used to create the row determines this). We're only interested in item and alternating item rows. We obtain the row type from the ItemType property of the current row in the DataListItemEventArgs object: Sub CheckTitle(objSender As Object, objArgs As DataListItemEventArgs) 'see what type of row (header, footer, item, etc.) caused the event Dim objItemType As ListItemType = CType(objArgs.Item.ItemType, ListItemType) 'only format the results if it's an Item or AlternatingItem event If objItemType = ListItemType.Item _ Or objItemType = ListItemType.AlternatingItem Then ... Once we know that this is a row we want to process, we can get the values from the DataItem property of this row. This returns a DataRowView object - basically a collection of the columns within this row. We can access the value of the column we want (in this case the Title column) by specifying the column name: ... 'objArgs.Item.DataItem returns the data for this row of items
  9. Dim objRowVals As DataRowView = CType(objArgs.Item.DataItem, DataRowView) 'get the value of the Title column Dim strTitle As String = objRowVals("Title") Now we can test the value to see if it's one that we want to modify. We're looking for book titles that contain the words "Active Server Pages" or "ADO". If we find one that matches, we use the FindControl method of the row to get a reference to the control with an ID value of TitleLabel. This is the control that we bound to the Title column within the definition of the DataList control earlier in our page. Once we get our reference to this control, we can append the extra text (Great for ASP Programmers!), putting it in a element that specifies the large red font style: If strTitle.IndexOf("Active Server Pages") >= 0 _ Or strTitle.IndexOf("ADO") >= 0 Then 'get a reference to the "Title" ASP:Label control in this row Dim objLabel As Label = _ CType(objArgs.Item.FindControl("TitleLabel"), Label) 'add a message to this Label control objLabel.Text += "   " _ & "Great for ASP Programmers!" End If End If End Sub If you look back at the screenshot, you'll see that this text appears only for the two books that contain our search text within their title. This gives us a useful technique for dynamically modifying the contents of a list control based on the
  10. current values of the data - something we can't always do by hard-coding logic into the page. This technique isn't limited to just adding text to a Label control. We could place other controls (such as elements) in the output of a DataList that are not visible, and then change their properties in the ItemDataBound event handler based on the values in the bound data. Or we could just change the formatting of existing bound content based on the current value. The possibilities are almost endless. Sorting and Filtering Rows in a DataGrid When we need to display more than a few rows of data, it's helpful for users to be able to sort the rows based on values in a specific column, and filter the rows based on the values in any column. Both techniques make it much easier for users to find what they are looking for. It means extra round-trips to the server using the current generation of controls, but it's a useful feature to add to your applications nonetheless. We can provide both these facilities easily when using a DataGrid control. The DataGrid can do most of the work required to provide a "sort by column" facility. And if the data source for the control is a DataView object, we can take advantage of the sorting and filtering features that it includes: To sort the rows within a DataView, we just have to set the Sort property to a string containing the name of the column, and optionally the keyword DESC to sort in descending order. We can sort by more than one column by separating the column names with a comma. To filter the rows that appear in the DataView, we set the RowFilter property to an expression that specifies the rows to be displayed. A simple example is "TitleLIKE'ASP'". More details on the Sort and RowFilter properties are provided in the upcoming data access chapters. The big advantage in using a DataGrid control is that it has a property named AllowSorting, and it exposes an event named SortCommand. When we set the AllowSorting property to True (usually done within the definition of the control), each column heading automatically becomes a hyperlink. When these are clicked, a postback occurs and the event handler specified for the SortCommand property is executed. You can see the way that we implement both sorting and filtering in the example page Sorting Rows and Finding Data in a DataGrid Control (sort-find-datagrid.aspx):
  11. How It Works The HTML section of this page contains the textbox and button used to filter the rows based on the title of the book. These controls are followed by the definition of the DataGrid that we use to display the matching titles: Select only Titles containing the text:
  12. HeaderStyle-BackColor="silver" HeaderStyle-HorizontalAlign="center" FooterStyle-BackColor="silver" ShowFooter="True" AllowSorting="True" OnSortCommand="SortRows" /> Other than some minimal styling information, the two properties we set for the DataGrid that are of interest here are the AllowSorting and OnSortCommand properties. These properties specify the appearance of the LinkButton controls that make up the column names in the header row, as well as the name of the event handler that is executed when one of the column names is clicked. The code section of the page contains three subroutines. As well as the Page_Load event handler, we have a BindDataGrid routine that is responsible for fetching the data sorted and filtered as required. The third routine, named SortRows, is executed when the column headings are clicked. You can see that it is attached to the DataGrid in the previous code listing as the OnSortCommand property. The page also defines two global (Page-level) variables that will hold the current sort order and filter expression: Dim gstrSortOrder As String 'to hold the sort order Dim gstrFindText As String 'to hold the filter expression Binding the DataGrid The first of the subroutines, named BindDataGrid, uses the same custom user control as some of the earlier examples to fetch a DataView object containing some book details from our data store. It then binds this DataView to our DataGrid control. However, it has a couple of other tasks to perform as well. It uses the two global variables to set the sort order of the rows in the DataView (by setting the Sort property) and it applies a filter to the rows to control which ones will be displayed (by setting the RowFilter property):
  13. Sub BindDataGrid() ... 'get dataset from get-dataset-control.ascx user control ... 'sort the rows in the DataView into the specified order objDataView.Sort = gstrSortOrder 'select the rows in the DataView that match the filter objDataView.RowFilter = gstrFindText 'set the DataSource property of the DataList and bind it MyDataGrid.DataSource = objDataView MyDataGrid.DataBind() End Sub The Page_Load Event Handler The second subroutine is the Page_Load event handler. This is executed when the page first loads, when the user clicks a column heading to change the sort order, or clicks the Find button to filter the rows that are displayed. In the event handler, if this is a postback, we change the global filter expression variable to reflect the value in the textbox. If it's the first time that the page has been loaded, we set default values for the textbox and the global string that specifies the sort order of the rows. The result is that we start out with the value "ASP" in the textbox when we first load the page, and from then on the global string variable will always hold the expression used to filter the rows. We also call our BindDataGrid subroutine (the one we just examined) each time the page is loaded, so that the DataView object and the grid are recreated with the current sort order and row filter:
  14. Sub Page_Load() If Page.IsPostBack Then 'set the value to be used for the RowFilter on the DataView gstrFindText = "Title LIKE '*" & txtFindText.Text & "*'" Else 'set the default values for the sort string and filter textbox gstrSortOrder = "ISBN" txtFindText.Text = "ASP" End If 'create the data set and bind to the DataGrid control BindDataGrid() End Sub Sorting the Rows in the DataGrid When our page is first loaded, the Page_Load event handler sets the Page-level variable holding the sort order to the value "ISBN", so the rows will be sorted in the order of the ISBN column values. But how do we change the sort order? Easy - the DataGrid control raises the SortCommand event whenever the user clicks on a column heading LinkButton. We specified our subroutine named SortRows as the handler for this event: Sub SortRows(objSender As Object, objArgs As DataGridSortCommandEventArgs) 'runs when the column headings in the DataGrid are clicked
  15. 'get the sort expression (name of the column heading that was clicked) gstrSortOrder = objArgs.SortExpression.ToString() 'recreate the data set and bind to the DataGrid control BindDataGrid() End Sub As you can see, the code required is minimal. The DataGridSortCommandEventArgs object that is automatically passed to our event handler when a column heading is clicked exposes a SortExpression property, which contains the name of the column. All we do is ensure that it's converted to a string and assign it to the Page-level "sort order" variable, then call the routine that recreates the DataView and binds it to our grid. Controlling the Size of the Viewstate One issue that we really must be aware of when using the ASP.NET list controls is the effect that they have on the amount of data being transmitted across the wire- with each postback and with each newly generated page. As we briefly discussed in the previous chapter, an ASP.NET page containing a server-side control automatically generates ViewState. This is an encoded representation of all the values in all the controls on the page, and it is persisted across page loads using a HIDDEN-type control. If you view the source of the page in your browser, you'll see something like this: ... ... If we place a list control on a page and fill it with data, all that data is encoded into the ViewState and passed across the wire with each page load and postback. In fact, it's even worse than that because, when the user loads the page, we're actually sending all the values twice - once as the visible output of the list control and once as the content of the ViewState. Of course, we might want this to occur as a feature of the way that the page works. If we create the output for the list control and bind it only during the first page load (and not during each postback) we depend on the ViewState to maintain
  16. the values in the list control. If getting the values from the data source is an expensive process in terms of resources or time, then persisting them in the ViewState is a good idea. However, if we are limited in bandwidth, or perhaps serving devices such as mobile phones that can't cope with large volumes of form content, then we might instead decide to recreate the values on each postback, and not include them in the ViewState. Bear in mind that this option requires a deliberate decision - if we take no action then the values will be included in the ViewState. Persisting List Control Values Automatically Across Postbacks If we are persisting values across postbacks, we can use the IsPostback property of the Page object so that the values are only created when the page is being executed for the first time. For example: Sub Page_Load() If Not Page.IsPostback Then objDataView = GetDataView(.....) 'get or build a DataView object MyDataGrid.DataSource = objDataView 'specify the data source MyDataGrid.DataBind() 'bind data to grid control End If End Sub Now, when the page is reloaded, the values that are automatically included in the ViewState will be used to populate the control. Preventing List Control Values from Being Persisted Across Postbacks There are occasions when we don't want to persist the values in a list control across postbacks. As well as the concern over bandwidth, we might have other reasons for recreating the data set or rebinding the list control each time we load the page. The simplest scenario is when the page does not actually include a element. Many of our previous examples were like this. They are not interactive pages, and so there is no requirement to post values back to the server - we just load the page and view it. In this case, there is no ViewState, but no user interaction either.
  17. However, if the page does contain a section, the values from the list control are automatically included in the ViewState. If the list control contains any interactive elements (such as buttons or edit controls where the value must be posted back to the server) the control has to be on an HTML . This is the case with the sorting and filtering example we've just been looking at, in which the column headings are automatically rendered as LinkButton controls. However, to sort and filter the rows, we have to rebind the data grid to the DataView object each time. We're actually recreating the whole DataSet and DataView with each postback, so we have no need to maintain the values in the ViewState. For this reason, we set the EnableViewState property of the DataGrid object to False in the control definition so that the contents of this control are not included in the ViewState:
  18. Of course, the other way to see how much ViewState is in a page is just to view the source in the browser so that you can see the HIDDEN-type control. From that you can get a good idea of the amount of data being sent to the client each time. Automatic Paging in a DataGrid Our final example of using the DataGrid control just to display data demonstrates the use of paging. When there are a large number of rows to display, sending them all to the client in one go doesn't make sense. The user will get impatient waiting for them all to arrive, and may find that they actually wanted to see something else instead. To prevent this aggravation and waste of bandwidth, it is usual to divide the output into pages containing 10 or 20 rows (depending on the content), and then provide navigation controls so that users can view other pages of rows as required. The DataGrid control makes it easy to provide a paging feature. It contains logic that can automatically create pages containing the number of rows we require, and it can render the navigation controls in a range of ways. We can also take over paging entirely and implement all the features ourselves in order to provide a custom interface. To turn on the automatic paging feature, we simply need to set the AllowPaging property of the DataGrid control to True, and specify the name of an event handler that will run when the PageIndexChanged event occurs. We usually set these properties when we define the control in the HTML of the page. We can also specify the position of the "Pager" navigation controls. By default they are located in the footer row of the grid, aligned on the left. Our example that uses the automatic paging feature is Using Automatic Paging with a DataGrid Control
  19. (paging-datagrid.aspx). This example also contains controls that can be used to specify other properties of the paging feature. For example we can specify the number of rows in each page, and the style of the navigation controls. After changing any of the property values, just click on one of the navigation links to reload the page with the new options set: How It Works As usual, the HTML section of our page starts with the controls where we can specify how the DataGrid behaves: 'Previous' Link Text:   'Next' Link Text: Paging Style:
  20. Numeric   Text Number of rows per Page: This is followed by the definition of the DataGrid control. We set the three properties that control the paging behavior: we set AllowPaging to True, specify that the paging controls should be right-aligned within the footer row, and specify that the event handler named ChangeGridPage (which we'll look at shortly) will be executed when the user selects a page using the paging controls: The Page_Load Event Handler When the page loads each time, either when the user opens the page for the first time or in response to a click by the user on the paging controls, our Page_Load event handler is executed. However, we only want to execute code when the page is first opened so we check the value of the IsPostback property first. If it's False, we can set the default values for the controls in the page, and then call the BindDataGrid subroutine to bind and display the source data values in the
Đồng bộ tài khoản