The GridView control we examined in the previous section is designed to display data as a table, with each row containing one data row (one record). However, sometimes it's useful to be able to display data one row at a time, especially when there is a large number of columns or when you want to be able to edit the values of each column without using the rather cramped in-line editing mode of the GridView . To provide a one-row-per-page feature for displaying and editing data, ASP.NET 2.0 includes the new DetailsView control. It can be used stand-alone with paging controls that allow the user to scroll through the rows or combined with a GridView control to provide a master-detail display. In fact, you have already seen DetailsView -like rendering in action in the previous section of this chapter. When serving a page containing a GridView to a small-screen or mobile device, ASP.NET automatically uses DetailsView -like rendering to create the details page containing all the columns from the current row. Using a Stand-Alone DetailsView ControlThe declaration and attribute set for the DetailsView control is similar to that of the GridView . When used on its own, however, you will need to either enable the paging feature in order to display the paging controls or add your own custom paging feature so that users can navigate through the rows. Listing 4.21 shows a declaration of a DetailsView control that turns on the paging features and specifies that the mode should be NextPrevFirstLast so that the usual four links are displayed (the default mode is Numeric , where a numbered link is displayed for each row). The declaration also specifies the relative URLs of the images to display for the paging controls and the text to use as the alt attribute of each one. Listing 4.21 Declaring a DetailsView Control<asp:DetailsView id="details1" DataSourceID="dvs1" runat="server" DataKeyNames="ShipperID" AllowPaging="True" PagerSettings-Mode="NextPrevFirstLast" PagerSettings-FirstPageImageUrl="f.gif" PagerSettings-FirstPageText="First Row" PagerSettings-PrevPageImageUrl="p.gif" PagerSettings-PrevPageText="Previous Row" PagerSettings-NextPageImageUrl="n.gif" PagerSettings-NextPageText="Next Row" PagerSettings-LastPageImageUrl="l.gif" PagerSettings-LastPageText="Last Row" /> <asp:SqlDataSource id="dvs1" runat="server" ConnectionString="server=localhost;database=Northwind;uid=x;pwd=x" SelectCommand="SELECT ShipperID,CompanyName,Phone FROM Shippers"> </asp:SqlDataSource> After the DetailsView control comes the declaration of the data source control. You can see that this is identical to the way it is used with a GridView control. The result is shown in the compound screenshot in Figure 4.6, with the paging controls and the alternate text captions visible. Figure 4.6. Navigating rows in a DetailsView control
The DetailsView control accepts the same styling attributes as the GridView control, so you can improve the appearance from the default shown here. You can also turn off automatic generation of the fields (by setting the AutoGenerateRows attribute to False ) and then specify the fields you want to display as well as their appearance and behavior. The DetailsView control uses a <RowFields> section in place of the <ColumnFields> section of the GridView control, but the same types of fields are used within it as in the GridView . You can declare your own sequence of BoundField , ButtonField , CheckBoxField , HyperLinkField , TemplateField , and CommandField controls within the <RowFields> section. Creating a Master-Detail Page with GridView and DetailsView ControlsFor rowsets that have a large number of columns, the one-row-per-page approach provided by the DetailsView control is useful. However, it does make it harder to navigate through and generally scan the data by eye. For that, the table layout provided by the GridView control is better. The ideal is to combine the two so that a few selected columns are displayed in the GridView , and the user can select a row to see it displayed with all the fields visible in the DetailsView . The two controls provide features that link them together declaratively , without requiring any code to be written. Listing 4.22 shows how this works. In this example, the GridView is bound to a data source control named dgs1 , and the DataKeyNames attribute specifies that the ShipperID column in the rowset exposed by that data source control is the primary key for each row. The AutoGenerateSelectButton attribute is set to True to display a Select link in each row, and the first row is selected when the page first loads. This is necessary because the DetailsView must have a current row to display. Listing 4.22 Master-Detail Pages: The GridView and SqlDataSource Controls<asp:GridView id="grid1" DataSourceID="dgs1" runat="server" DataKeyNames="ShipperID" SelectedIndex="0" AutoGenerateSelectButton="True" /> <asp:SqlDataSource id="dgs1" runat="server" ConnectionString="server=localhost;database=Northwind;uid=x;pwd=x" SelectCommand="SELECT ShipperID,CompanyName,Phone FROM Shippers" /> ... Linking a GridView and DetailsView ControlThe DetailsView control is declared next (see Listing 4.23). It is bound to the second data source control on the page, named dvs1 , and again has the primary key column identified by the DataKeyNames attribute. The data source control has the same SelectCommand as the previous one, though it doesn't have toif you display a different selection of columns in the two controls, you can select just the columns you need. The link between the two data source controls, which ensures that the row selected in the GridView is displayed in the DetailsView control, is the addition of a filter to the second data source control. The FilterExpression declares a parameter @ShipperID , and the FilterParameters section of the control contains a ControlParameter that is bound to the SelectedValue property of the GridView control. As the user selects rows in the GridView control, the SelectedValue is automatically set to the ID of that row and thus filters the data source control that powers the DetailsView control on that ID value. Listing 4.23 Master-Detail Pages: The DetailsView and Filtered SqlDataSource Controls... <asp:DetailsView id="details1" DataSourceID="dvs1" runat="server" DataKeyNames="ShipperID" /> <asp:SqlDataSource id="dvs1" runat="server" ConnectionString="server=localhost;database=Northwind;uid=x;pwd=x" SelectCommand="SELECT ShipperID,CompanyName,Phone FROM Shippers" FilterExpression="ShipperID=@ShipperID"> <FilterParameters> <asp:ControlParameter Name="ShipperID" ControlID="grid1" PropertyName="SelectedValue" /> </FilterParameters> </asp:SqlDataSource> The result can be seen in Figure 4.7. A Select link appears in each row of the GridView control, and clicking one displays that row in the DetailsView control below it. Figure 4.7. Selecting a row in a master-detail page
Inserting and Editing Rows with a DetailsView ControlA task that is regularly required when working with data rows, and which is quite complex to achieve in ASP.NET 1.0, is inserting a new row into the source data table. In ASP.NET 2.0, with a GridView control, this can be achieved by using a DetailsView control instance declared separately on the page. The technique is very similar to that just seen for creating a master-detail page. First, a GridView control is declared and then the associated data source control that supplies the rows (see Listing 4.24). Listing 4.24 Inserting and Editing Rows: The GridView and SqlDataSource Controls for Lookups<asp:GridView id="grid1" DataSourceID="dgs1" runat="server" DataKeyNames="ShipperID" SelectedIndex="0" AutoGenerateSelectButton="True" /> <asp:SqlDataSource id="dgs1" runat="server" ConnectionString="server=localhost;database=Northwind;uid=x;pwd=x" SelectCommand="SELECT ShipperID,CompanyName,Phone FROM Shippers" /> ... Enabling Editing in a DetailsView ControlTo enable row edits, row deletes, and/or row inserts in a DetailsView control, you just add the relevant attributes to the control declaration. The first four highlighted attributes in Listing 4.25 turn on display of the Insert, Edit, Delete, and Cancel links, respectively (the Update link always appears when editing is enabled). For the automatic no-code updates to work, you also have to provide the relevant SQL statements or stored procedures. The highlighted attributes for the data source control in Listing 4.25 show the UPDATE , DELETE , and INSERT statements that will push changes to the rows back into the database. Listing 4.25 Inserting and Editing Rows: The DetailsView and SqlDataSource Controls for Edits... <asp:DetailsView id="details1" DataSourceID="dvs1" runat="server" DataKeyNames="ShipperID" AutoGenerateInsertButton="True" AutoGenerateEditButton="True" AutoGenerateDeleteButton="True" AutoGenerateCancelButton="True" OnItemDeleting="CheckDelete" OnItemUpdated="UpdateGrid" OnItemInserted="UpdateGrid" OnItemDeleted="UpdateGrid" /> <asp:SqlDataSource id="dvs1" runat="server" ConnectionString="server=localhost;database=Northwind;uid=x;pwd=x" SelectCommand="SELECT ShipperID,CompanyName,Phone FROM Shippers" UpdateCommand="UPDATE Shippers SET CompanyName=@CompanyName, Phone=@Phone WHERE ShipperID=@ShipperID" DeleteCommand="DELETE FROM Shippers WHERE ShipperID=@ShipperID" InsertCommand="INSERT INTO Shippers (CompanyName, Phone) VALUES (@CompanyName, @Phone)" FilterExpression="ShipperID=@ShipperID" > <FilterParameters> <asp:ControlParameter Name="ShipperID" ControlID="grid1" PropertyName="SelectedValue" /> </FilterParameters> </asp:SqlDataSource> <asp:Label id="lblError" EnableviewState="False" runat="server" /> The screenshot in Figure 4.8 shows two views of the process of editing a row. The DetailsView displays the Edit, Delete, and New links. Clicking the Edit link switches the DetailsView into edit mode, and the values of the non-key fields can be edited. Figure 4.8. Editing a row with a DetailsView control
It's also possible to insert a row by clicking the New link, entering the values, and then clicking the Insert link (see Figure 4.9). Notice that the primary key is displayed as a text box so that the user can enter an appropriate value. Figure 4.9. Inserting a row with a DetailsView control
In our case, however, the primary key column within the database table is auto-generated (an IDENTITY column). You don't need to enter a value, and the INSERT statement declared for the InsertCommand property of the data source control does not attempt to apply any value that you might enter anyway. You could create the fields for the DetailsView control manually, by setting the AutoGenerateRows attribute to False and using a BoundField with the InsertVisible property set to False , or by using a TemplateField , so that the value is not editable. Handling DetailsView Control EventsThere are a couple of other issues to look at as well. Although the GridView and DetailsView controls are linked so that the DetailsView displays the row currently selected in the GridView , changes to the rows during editing (within the DetailsView ) are not automatically displayed in the GridView control. However, like the GridView , the DetailsView control exposes events that occur as rows are being manipulated. By handling these events you can link the controls together so that each reflects any changes made in the other. The declaration of the DetailsView control shown in Listing 4.25 and repeated in Listing 4.26 for convenience includes four attributes that specify event handlers that will be executed in response to the ItemDeleting , ItemUpdated , ItemInserted , and ItemDeleted events. Listing 4.26 The Event Attribute Declarations for the DetailsView Control<asp:DetailsView id="details1" DataSourceID="dvs1" runat="server" DataKeyNames="ShipperID" AutoGenerateInsertButton="True" AutoGenerateEditButton="True" AutoGenerateDeleteButton="True" AutoGenerateCancelButton="True" OnItemDeleting="CheckDelete" OnItemUpdated="UpdateGrid" OnItemInserted="UpdateGrid" OnItemDeleted="UpdateGrid" /> Preventing the Original Rows from Being DeletedThe ItemDeleting event occurs just before a row is deleted in the DetailsView control, and the page handles this to prevent attempts to delete the existing rows in the table (as shown earlier for the GridView control). Other than the fact that this event handler takes a DetailsViewDeleteEventArgs instance as the second argument, rather than the GridViewDeleteEventArgs instance used in the earlier example, the code is identical (see Listing 4.27). Listing 4.27 The Event Handler for the ItemDeleting Event<script runat="server"> Sub CheckDelete(oSender As Object, _ oArgs As DetailsViewDeleteEventArgs) Dim iKey As Integer = oArgs.Keys(0) If iKey < 4 Then oArgs.Cancel = True lblError.Text = "Cannot delete the original rows from the table" End If End Sub </script> Updating the GridView Display with New or Changed Row ValuesThe other three event attribute declarations specify that the event handler named UpdateGrid will be executed after a row has been updated, inserted, or deleted. All the code has to do in this case is call the DataBind method of the GridView control so that it shows the changes to the rows made in the DetailsView control (see Listing 4.28). However, when a row is deleted, the currently selected row in the GridView is null, and this will cause an error when it tries to redisplay this row in the DetailsView control. To prevent this, the SelectedIndex property of the GridView is set to (the first row, which cannot be deleted). Listing 4.28 Displaying the Changed DataSub UpdateGrid(oSender As Object, oArgs As DetailsViewStatusEventArgs) grid1.DataBind() grid1.SelectedIndex = 0 End Sub Another situation where event handling might be useful is to highlight the current row in the GridView control when the user navigates through the rows using the DetailsView pager controls. The GridView would need to have a different style defined for the selected row (using the SelectedItemTemplate ). Code that handles the DataItemIndexChanged event for the DetailsView would just set the SelectedIndex property of the GridView to the appropriate row index. This automatically displays the new row in the appropriate way. The DetailsView Control InterfaceAs noted earlier, and as you'll have seen from the examples above, the DetailsView control interface is similar to that of the GridView . This isn't surprising because they both do effectively the same thingdisplay rows of data. The main difference is that the GridView displays the rows horizontally as a table, with the fields in columns, while the DetailsView displays each row as a separate single page with the fields laid out vertically. However, for completeness, the following sections list the members of the DetailsView that are not found in the GridView . Properties Specific to the DetailsView ControlThe DetailsView control does not support sorting and thus has none of the properties associated with this feature that apply to the GridView control. And the different ways that the rows are displayed mean that there is no concept of a selected row in a DetailsView , so there is no AutoGenerateSelectButton or selected row style properties. Properties that are available for the DetailsView control, and not for the GridView control, include those listed in Table 4.13. Table 4.13. The Properties of the DetailsView Control
Events Specific to the DetailsView ControlThe DetailsView control has the same DataBinding and DataBound events as the GridView , but the remaining events are specific to the DetailsView control (see Table 4.14). Table 4.14. The Events of the DetailsView Control
|