Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 40 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
40
Dung lượng
1,14 MB
Nội dung
'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): 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: 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 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 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 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 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: 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 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 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") >= _ Or strTitle.IndexOf("ADO") >= 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 current values of the data - something we can't always 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 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): as we'll see later in this example The next three attributes in the opening DataGrid tag are used to specify the names of the event handlers that will be executed in response to the user clicking the Edit, Update, and Cancel links that the EditCommandColumn will generate for us Finally, we set the AutoGenerateColumns property to False as we want to create our own column structure for the grid: As we've turned off automatic generation of the columns we must specify the columns that we want to appear within the definition We include a BoundColumn that displays values from the ISBN column in our data source, a custom TemplateColumn that displays the Title, followed by another BoundColumn that displays the PublicationDate We included the attribute ReadOnly="True" for the ISBN column as we don't want the user to be able to edit values in this column (as it is the primary key of the source table) We used a custom TemplateColumn instead of a BoundColumn for the Title column for a couple of reasons Firstly, the automatic editing feature displays a textbox instead of a simple text value in all the columns that are not read-only However, this textbox isn't large enough to comfortably accommodate a long string, so we need to specify the editing control ourselves and make it 60 characters long Secondly, this gives us the chance to see how we can provide non-standard edit controls for a column if required We just specify an element to be used to display the column values in normal mode, and an element that defines the control to be used in edit mode: As you can see from the code, the last column is the EditCommandColumn we mentioned earlier While there are plenty of attributes that we can apply to this column to control the formatting (basically the same as for the list controls themselves such as the font style, column heading, wrapping behavior, and so on), we've just specified the text we want to use for the three commands that can appear in this column That completes the definition of our DataGrid control The Page_Load Event Handler When the page first loads, we must create the rowset set we are using as the source of the DataGrid control We this in the Page_Load event handler, but only if this is not a postback(as we've seen in plenty of earlier examples): Sub Page_Load() If Not Page.IsPostback Then BindDataGrid() 'create dataset and bind to grid control End If End Sub The BindDataGrid routine is responsible for fetching the data from the database through a DataReader object, binding it to the control, then calling the DataBind method of the DataGrid to display the data Again, this is the same routine as we've used in previous examples: Sub BindDataGrid() 'create a DataReader object to retrieve the data MyDataGrid.DataSource = objDataReader MyDataGrid.DataBind() End Sub Displaying the UPDATE SQL Statement Another subroutine that we use in this page is responsible for displaying the SQL statement that we generate in a Label control in the HTML section at the top of the page: This routine, named ExecuteSQLStatement, would normally be responsible for executing the SQL statement against the back-end database or other data source in order to update the values in line with the edits made in the DataGrid However, in this example page, we just display the SQL statement: Sub ExecuteSQLStatement(strSQL) lblSQL.Text = "The SQL statement is: " & strSQL End Sub Handling Item Edit Events All that remains is to handle the three events we specified in the definition of the DataGrid control We have to react to the EditCommand, UpdateCommand, and CancelCommand events The EditCommand event is raised when the user clicks the Edit link in any row within the grid For this event, we specified our DoItemEdit event handler routine Within this routine, we first clear any existing SQL statement from the Label at the top of the page (to avoid any confusion) Then we set the EditItemIndex property of the DataGrid control to the index of the row that contained the Edit link the user clicked: Sub DoItemEdit(objSource As Object, objArgs As DataGridCommandEventArgs) lblSQL.Text = "" 'clear text from label that shows SQL statement 'set the EditItemIndex property of the grid to this item's index MyDataGrid.EditItemIndex = objArgs.Item.ItemIndex BindDataGrid() 'bind the data and display it End Sub We get this index from the parameters of the event handler - our code is passed a DataGridCommandEventArgs object that exposes the ItemIndex property of the Item that was selected Finally we rebind the grid to display the new layout The default value of the EditItemIndex property is -1, which indicates that none of the rows is in "edit mode" When the DataGrid control comes to render the grid, it will detect that the EditItemIndex has been set to a different value, and will automatically render the specified row with the contents of our element, or with textboxes instead of plain text for ordinary bound columns where we haven't specified a custom element Handling the Update and Cancel Events Now that we've got our grid into "edit mode", we just need to handle the Update and Cancel events We specified that a click on the Cancel link should execute our event handler named DoItemCancel In this event handler, all we need to is switch the grid back out of "edit mode" by setting the EditItemIndex property back to -1: Sub DoItemCancel(objSource As Object, objArgs As DataGridCommandEventArgs) 'set EditItemIndex property of grid to -1 to switch out of Edit mode MyDataGrid.EditItemIndex = -1 BindDataGrid() 'bind the data and display it End Sub However, if the user clicks the Update link, our DoItemUpdate event handler will be called Here, we have to create a suitable SQL statement, or execute some stored procedure or other code to update the original source data We're just generating a simple SQL UPDATE statement in our example, and for this we need to get the edited values from the DataGrid row that the user is working on We've used two different techniques in this example (in order to illustrate the options and show how it can be done) After declaring two variables to hold references to the textboxes that contain the edited values, we first access the Title textbox (named txtTitle) using the FindControl method of the Item that is contained in the DataGridCommandEventArgs object (which was passed to our event handler as a parameter) We have to convert (cast) the return value to the correct type - in this case a TextBox object: Sub DoItemUpdate(objSource As Object, objArgs As DataGridCommandEventArgs) 'get a reference to the title and publication date textboxes Dim objTitleCtrl, objPubDateCtrl As TextBox objTitleCtrl = CType(objArgs.Item.FindControl("txtTitle"), TextBox) objPubDateCtrl = objArgs.Item.Cells(2).Controls(0) For the second textbox, we are accessing the Cells collection for the Item contained in the DataGridCommandEventArgs object From the third cell in the row (our PublicationDate column), we can use the Controls collection of that cell to get a reference to the textbox it contains This technique is best used when the column is a normal BoundColumn or auto-generated column - it doesn't work with a custom column created with templates (which is why we used the FindControl technique with our Title column) Once we've got references to the two controls, we can create the SQL UPDATE statement and call our ExecuteSQLStatement routine to execute it against the data source (or, in our example page, just display it) We get the value of the primary key for the current row (the ISBN) from the DataKeys collection Recall that we included the attribute DataKeyField="ISBN" in the definition of our DataGrid control, so we can get the value of the ISBN column for this row using the row index against the DataKeys collection: 'create a suitable SQL statement and execute it Dim strSQL As String strSQL = "UPDATE Booklist SET Title='" & objTitleCtrl.Text & "', " _ & "PublicationDate='" & objPubDateCtrl.Text & "' " _ & "WHERE ISBN='" & MyDataGrid.DataKeys(objArgs.Item.ItemIndex) & "'" ExecuteSQLStatement(strSQL) 'set EditItemIndex property of grid to -1 to switch out of Edit mode MyDataGrid.EditItemIndex = -1 BindDataGrid() 'bind the data and display it End Sub We finish off by switching the grid back out of "edit mode" by setting the EditItemIndex property of the DataGrid control back to -1, and rebind the control to display the result It's taken a while to explain this example, but there really isn't a lot of code in it The code that is required is relatively simple and well structured We are just reacting to events that the DataGrid control raises, so debugging and modifying the page is far less error-prone than with any technique we might have used to the same thing in previous versions of ASP Selecting and Editing Data with a DataList Control The second control that provides in-line editing capabilities automatically is the DataList In fact, we can more with this control as far as selecting or editing data goes, but it requires more code and greater effort to use One additional feature it has is the ability to easily switch the control into "selected" mode, where one row becomes the current row and is highlighted by applying different styles or formatting to that row The example page Selecting and Editing Data in a DataList Control (select-edit-datalist.aspx) demonstrates both selecting and editing rows in a DataList control When first opened, it displays a list of book titles Each one has an Info button at the left-hand end of the row If we click one of these buttons, that row becomes selected - and both the format and content change to reflect this: An Edit button also appears in the selected row When we click this button, that row goes into "edit mode" The book title and publication date appear in textboxes where they can be edited At the same time, three other buttons appear in the row - allowing us to update the row with our changes, delete the current row, or cancel our updates: When we select the Update or Delete option, a suitable SQL UPDATE or DELETE statement is generated and displayed in the page (as in the previous example it doesn't actually execute the statement against the data store): How It Works While this example looks quite different from the previous DataGrid example, they have a lot of similarities and they share a lot of code The HTML section of the page contains a , and within this is the definition of the DataList control In this case, we have some extra style properties, because we now have a "selected mode" as well as an "edit mode" As before, we set the DataKeyField attribute to "ISBN"(the name of the primary key column in our data source) We also have to specify the event handlers for our edit commands In this case, we have to react to the ItemCommand event as well, so that we can detect a click on the Info button and put that row into "selected mode": The remainder of the control definition contains the four templates we need There is a element that defines what appears at the top of the control, followed by the element that defines the normal content for rows that are not selected or being edited We use an ordinary ASP:Button control for the Info button in each row, with the CommandName property set to Select, and we just display this button and the book title: Some Wrox Press Books: Next is the element, which is used for the row that is currently in "selected mode" This is the row specified by the SelectedIndex property of the DataList (as with the EditItemIndex property of the DataGrid control, the value of this property is -1 if no row is selected) For the selected row, we display the book title, a button with the caption and CommandName value of Edit, the ISBN for this book, and the publication date: Title: ISBN: Published: This provides the "selected row" appearance we saw in the earlier screenshots: The Edit button will be used to put the DataList row into "edit mode" When this happens, the control will use the contents of the element to render the content for this row We display the ISBN followed by the Update, Delete, and Cancel, buttons Then, on the next line, we display two textboxes that are bound to the Title and PublicationDate columns in the data source: ISBN: Title: PublicationDate: This is a deliberate design feature of our example page, and not a requirement In your own applications you are free to put a row into "edit mode" without having to put it into "selected mode" first - as we did with the previous DataGrid example Meanwhile, in this example the row we're editing looks like this when we're in "edit mode": The Page_Load event handler is the same as we used for the previous DataGrid example, as is the BindDataGrid routine The page also contains the same ExecuteSQLStatement routine that displays the SQL statement we'll build when the Update or Delete buttons are clicked What are slightly different are the routines that perform the switch to "selected mode" and "edit mode", and those that generate the SQL statements Selecting a Row The ItemCommand event handler, for which we specified our routine DoItemSelect, is executed when any command button or link within the rows of the control is clicked All we need to to select a row in our DataList is set the SelectedIndex property of the control Before we this, we clear any existing text from the Label control at the top of the page that displays our SQL UPDATE or DELETE statements However, there is an important issue to be aware of here We specified other command buttons in the templates for our DataList - those that activate the Update, Delete, and Cancel commands when the grid is in "edit mode" These three events will automatically call the event handlers that we specified when we defined the control But they also call the ItemCommand event handler - they raise the ItemCommand event as well as their "own" event This means that we must check which control was used to raise the event in the ItemCommand event handler (our DoItemEvent routine) We only select the row if it is the Info button, which has the CommandName value of Select: Sub DoItemSelect(objSource As Object, objArgs As DataListCommandEventArgs) lblSQL.Text = "" 'clear any content from SQL statement Label 'see if it was the Select button that was clicked If objArgs.CommandName = "Select" Then 'set the SelectedIndex property of the list to this item's index MyDataList.SelectedIndex = objArgs.Item.ItemIndex BindDataGrid() 'bind the data and display it End If End Sub Now, the grid will automatically render our contents for the row indicated by the SelectedIndex property Editing a Row Once we put a row into "selected mode" in our example, it displays a button that can be used to put that row into "edit mode" The Edit button has the CommandName value Edit, which means that it will raise the EditCommand event (as well as the ItemCommand event) when clicked We specified our DoItemEdit routine as the event handler for the EditCommand event, and in it we first "unselect" this row by setting the SelectedIndex property of the control to -1, and then set the EditIndex property to this row index and rebind the grid: Sub DoItemEdit(objSource As Object, objArgs As DataListCommandEventArgs) 'set the SelectedIndex propery of the list to -1 to "unselect" it MyDataList.SelectedIndex = -1 'set the EditItemIndex property of the list to this item's index MyDataList.EditItemIndex = objArgs.Item.ItemIndex BindDataGrid() 'bind the data and display it End Sub Now, the contents of the will be used when this row is rendered Updating a Row Once in "edit mode", the row displays the Update, Delete, and Cancel buttons The Update button has the CommandName value Update, and so it will raise the UpdateCommand event when clicked This will execute our routine named DoItemUpdate, which we specified as the handler for this event in the definition of the DataList control In this routine, we almost exactly the same as we did in the previous DataGrid example We get a reference to the txtTitle and txtPubDate textboxes in this row, and use their values to build a SQL statement to update the row in the original data source Again, we get the ISBN (the primary key for the row) from the DataKeys collection Then, after executing the SQL statement (or, in our example, just displaying it), we switch the row out of "edit mode" by setting the EditItemIndex of the DataList control to -1, and rebind the control to display the updated results: Sub DoItemUpdate(objSource As Object, objArgs As DataListCommandEventArgs) 'get a reference to the title and publication date textboxes Dim objTitleCtrl, objPubDateCtrl As TextBox objTitleCtrl = CType(objArgs.Item.FindControl("txtTitle"), TextBox) objPubDateCtrl = CType(objArgs.Item.FindControl("txtPubDate"), TextBox) 'create a suitable SQL statement and execute it Dim strSQL As String strSQL = "UPDATE Booklist SET Title='" & objTitleCtrl.Text & "', " _ & "PublicationDate='" & objPubDateCtrl.Text & "' " _ & "WHERE ISBN='" & MyDataList.DataKeys(objArgs.Item.ItemIndex) & "'" ExecuteSQLStatement(strSQL) 'set EditItemIndex property of grid to -1 to switch out of Edit mode MyDataList.EditItemIndex = -1 BindDataGrid() 'bind the data and display it End Sub Deleting a Row The DeleteCommand event handler we specified in our definition of the DataList control is the routine named DoItemDelete This is a relatively simple routine when compared to the "update" event handler We build a SQL DELETE statement, using the ISBN value obtained from the DataKeys collection, execute it, switch the row back out of "edit mode", and rebind the grid to display the results: Sub DoItemDelete(objSource As Object, objArgs As DataListCommandEventArgs) 'create a suitable SQL statement and execute it Dim strSQL As String strSQL = "DELETE FROM Booklist WHERE ISBN='" _ & MyDataList.DataKeys(objArgs.Item.ItemIndex) & "'" ExecuteSQLStatement(strSQL) 'set EditItemIndex property of grid to -1 to switch out of Edit mode MyDataList.EditItemIndex = -1 ... the SDK and the QuickStart samples included with ASP.NET Editing Data with Data-bound Controls The final topic for this chapter shows a rather more specialized technique for use with the DataList... 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... 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