The DetailsView Control





The DetailsView Control

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 inline 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 in stand-alone mode where paging controls that allow the user to scroll through the rows are provided. Alternatively it can be 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 such rendering to create the details page containing all the columns from the current row.

Using a Stand-Alone DetailsView Control

The declaration and attribute set for the DetailsView control is similar to that of the GridView. When used on its own, however, you 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 NextPreviousFirstLast 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.

An Example of Using a DetailsView Control
<asp:DetailsView  DataSource runat="server"

  DataKeyNames="ShipperID" AllowPaging="True"

  PagerSettings-Mode="NextPreviousFirstLast"

  PagerSettings-FirstPageImageUrl="f.gif"

  PagerSettings-FirstPageText="First Row"

  PagerSettings-PreviousPageImageUrl="p.gif"

  PagerSettings-PreviousPageText="Previous Row"

  PagerSettings-NextPageImageUrl="n.gif"

  PagerSettings-NextPageText="Next Row"

  PagerSettings-LastPageImageUrl="l.gif"

  PagerSettings-LastPageText="Last Row" />



<asp:SqlDataSource  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 compound screenshot in Figure shows the result, with the paging controls and the alternate text captions visible.

6. Navigating rows in a DetailsView control

graphics/04fig06.gif


The DetailsView control accepts basically the same set of 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.

Note that 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.

The other main difference is in the names of the nested styling elements you can place within a DetailsView control declaration. Instead of ItemStyle, AlternatingItemStyle, and EditItemStyle, you use RowStyle, AlternatingRowStyle, and EditRowStyle. There is also a CommandRowStyle that sets the style of the row containing the Edit, Update, and Cancel links when editing is enabled in a DetailsView control. Other differences between the attributes and properties of the GridView and DetailsView controls are listed in Figure later in this chapter.

The Properties Specific to the DetailsView Control

Property

Description

AutoGenerateRows

Sets or returns a Boolean value that indicates whether the control will automatically generate fields for each column in the source data rowset.

AutoGenerateInsertButton

Sets or returns a Boolean value that indicates whether the control will automatically generate a New button for each row.

DataKey

Returns a DataKey instance containing the keys and values corresponding to the key names specified by the DataKeyNames attribute.

DataItemIndex

Sets or returns an Integer value that is the zero-based index of the DataItem (row) currently displayed.

DataItemCount

Returns an Integer value that is the total number of rows in the underlying data source bound to the control.

DefaultMode

Sets or returns a value from the DetailsViewMode enumeration that specifies how the fields are displayed when the page loads and after Cancel, Update, Delete, or New is pressed. Valid values are ReadOnly (the default), Edit, and Insert.

CurrentMode

Returns a value from the DetailsViewMode enumeration that indicates the current mode of the DetailsView.

InsertVisible

Sets or returns a Boolean value that indicates whether this field will be displayed when inserting a new row into the source rowset.

HeaderText

Sets or returns a String that is the text to be displayed immediately above the fields in the output generated by the control.

Rows

Contains a DetailsViewRow object for each row in the DetailsView.

RowFields

Returns a DataControlFieldCollection instance that is a collection of all the DataControlField objects that generate the output for the control.


Creating a Master-Detail Page with GridView and DetailsView Controls

For 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.

Master-Detail Pages: The GridView and SqlDataSource Controls
<asp:GridView  DataSource runat="server"

     DataKeyNames="ShipperID" SelectedIndex="0"

     AutoGenerateSelectButton="True" />



<asp:SqlDataSource  runat="server"

  ConnectionString="server=localhost;database=Northwind;uid=x;pwd=x"

  SelectCommand="SELECT ShipperID,CompanyName,Phone FROM Shippers" />

...


The 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 to—if you display a different selection of columns in the two controls, you can select just the columns you need.

Master-Detail Pages with a DetailsView and Filtered SqlDataSource
...

<asp:DetailsView  DataSource runat="server"

     DataKeyNames="ShipperID" />



<asp:SqlDataSource  runat="server"

  ConnectionString="server=localhost;database=Northwind;uid=x;pwd=x"

  SelectCommand="SELECT ShipperID,CompanyName,Phone FROM Shippers"

  FilterExpression="[email protected]">



  <FilterParameters>

    <asp:ControlParameter Name="ShipperID" Control

                          PropertyName="SelectedValue" />

  </FilterParameters>



</asp:SqlDataSource>


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.

By default, the first data row in the source rowset is selected when the page loads. 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.

Figure shows the result. A Select link appears in each row of the GridView control, and clicking one displays that row in the DetailsView control below it.

7. Selecting a row in a master-detail page

graphics/04fig07.gif


Inserting and Editing Rows with a DetailsView Control

A task that is regularly required when working with data rows, one that 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, you can do this 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 together with the associated data source control that supplies the data (see Listing 4.24).

Inserting and Editing Rows with a GridView and SqlDataSource
<asp:GridView  DataSource runat="server"

  DataKeyNames="ShipperID" SelectedIndex="0"

  AutoGenerateSelectButton="True" />



<asp:SqlDataSource  runat="server"

 ConnectionString="server=localhost;database=Northwind;uid=x;pwd=x"

 SelectCommand="SELECT ShipperID,CompanyName,Phone FROM Shippers" />

...


Enabling Editing in a DetailsView Control

To 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 attributes set in bold 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 other attributes set in bold 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.

Inserting and Editing Rows with a DetailsView and SqlDataSource
...

<asp:DetailsView  DataSource runat="server"

     DataKeyNames="ShipperID"

     AutoGenerateInsertButton="True" AutoGenerateEditButton="True"

     AutoGenerateDeleteButton="True" AutoGenerateCancelButton="True"

     OnItemDeleting="CheckDelete" />



<asp:SqlDataSource  runat="server"

  ConnectionString="server=localhost;database=Northwind;uid=x;pwd=x"

  SelectCommand="SELECT ShipperID,CompanyName,Phone FROM Shippers"

  UpdateCommand="UPDATE Shippers SET [email protected],

                 [email protected] WHERE [email protected]"

  DeleteCommand="DELETE FROM Shippers WHERE [email protected]"

  InsertCommand="INSERT INTO Shippers (CompanyName, Phone)

                 VALUES (@CompanyName, @Phone)"

  FilterExpression="[email protected]" >



  <FilterParameters>

    <asp:ControlParameter Name="ShipperID" Control

                          PropertyName="SelectedValue" />

  </FilterParameters>



</asp:SqlDataSource>



<asp:Label  EnableviewState="False" runat="server" />


The screenshot in Figure 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.

8. Editing a row with a DetailsView control

graphics/04fig08.gif


It's also possible to insert a row by clicking the New link, entering the values, and then clicking the Insert link (see Figure). Notice that the primary key is displayed as a text box so that the user can enter an appropriate value.

9. Inserting a row with a DetailsView control

graphics/04fig09.jpg


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 Events

The declaration of the DetailsView control shown in Listing 4.25 (and repeated in Listing 4.26 for convenience) includes an attribute that specifies the event handler that will be executed in response to the ItemDeleting event.

The OnItemDeleting Event Attribute Declaration
<asp:DetailsView  DataSource runat="server"

     DataKeyNames="ShipperID"

     AutoGenerateInsertButton="True" AutoGenerateEditButton="True"

     AutoGenerateDeleteButton="True" AutoGenerateCancelButton="True"

     OnItemDeleting="CheckDelete" />


The 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).

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>


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 Interface

As noted earlier, and as you've seen from the earlier examples, the DetailsView control interface is similar to that of the GridView. This isn't surprising because they both do effectively the same thing—display 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 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 Control

The 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 Figure.

The TemplateField in the DetailsView Control

Although the types of field controls you can use in a DetailsView control are the same as those you use in a GridView control, the TemplateField control has some extra properties when used in a DetailsView control. This is because the DetailsView control allows new rows to be inserted, which the GridView control does not. The extra properties are detailed in Figure. For the same reason, the DetailsView also allows you to include a nested <InsertItemTemplate> section within a TemplateField declaration.

The TemplateField Properties Specific to the DetailsView

Property

Description

ShowInsertButton

Sets or returns a Boolean value that indicates whether an Insert button will be displayed in this column.

NewText

Sets or returns a String value that is the caption for the button that adds an empty row to the rowset and displays this empty row in edit mode with the Insert and Cancel buttons visible. The default caption for this button is New.

NewImageUrl

Sets or returns a String that is the relative or absolute URL of the image to display in place of a text New link.

InsertText

Sets or returns a String value that is the caption for the button that inserts the new row into the grid after the user has filled in the values. The default is Insert.

InsertImageUrl

Sets or returns a String that is the relative or absolute URL of the image to display in place of a text Insert link.


Note that if you want to be able to perform updates to the source data from a TemplateField column when using a data source control to populate the DetailsView control, you must use the new two-way data binding syntax. See the Two-Way Data Binding Syntax for Templated Controls section near the end of this chapter for more details.

Events Specific to the DetailsView Control

The DetailsView control has the same DataBinding and DataBound events as the GridView, but the remaining events are specific to the DetailsView control (see Figure).

The Events of the DetailsView Control

Event

Description

DataItemIndexChanging

Raised before the DetailsView control changes from one row to the next. Passes a DetailsViewItemEventArgs instance to the event handler, which exposes the following properties:

  • Cancel: A Boolean property that can be set to True to prevent the control from changing to the new row.

  • NewDataItemIndex: The zero-based Integer index of the row that will be displayed next.

DataItemIndexChanged

Raised after the DetailsView control changes from one row to the next. Passes a standard EventArgs instance to the event handler.

ItemCommand

Raised when any control in the DetailsView causes a postback. Passes a DetailsViewCommandEventArgs instance to the event handler, which exposes the following properties:

  • CommandArgument: The value of the CommandArgument property of the button that raised the event.

  • CommandName: The CommandName property of the control that caused the postback as a String.

  • CommandSource: An Object reference to the control that caused the postback.

ItemCreated

Raised when a new row is created in the DetailsView control. Passes a standard EventArgs instance to the event handler.

ItemDeleting

Raised before the data source control bound to the DetailsView deletes a row. Passes a DetailsViewDeleteEventArgs instance to the event handler, which exposes the following properties:

  • Cancel: A Boolean property that can be set to True to cancel the delete operation.

  • Keys: An IOrderedDictionary instance containing the primary key values for the row.

  • Values: An IOrderedDictionary instance containing the non-key values currently in the row.

  • RowIndex: An Integer value indicating the index of the row within the data source rowset.

ItemDeleted

Raised after the data source control bound to the DetailsView deletes a row. Passes a DetailsViewDeletedEventArgs instance to the event handler, which exposes the following properties:

  • Keys: An IOrderedDictionary instance containing the primary key values for the row.

  • Values: An IOrderedDictionary instance containing the non-key values from the deleted row.

  • AffectedRows: The number of rows that were deleted.

  • Exception: An Exception instance returned if the delete process fails. A reference to the actual exception that was raised by the database can be obtained from the InnerException property of this current exception.

  • ExceptionHandled: A Boolean value that you can set to True after handling any exception raised by the delete process to indicate that this exception should not be raised to the code that called this method.

ItemInserting

Raised before the data source control bound to the DetailsView inserts a new row. Passes a DetailsViewInsertEventArgs instance to the event handler, which exposes the following properties:

  • Cancel: A Boolean property that can be set to True to cancel the insert operation.

  • CommandArgument: The value of the CommandArgument property of the control that raised the event.

  • Values: An IOrderedDictionary instance containing the values for the new row.

ItemInserted

Raised after the data source control bound to the DetailsView inserts a new row. Passes a DetailsViewInsertedEventArgs instance to the event handler, which exposes the following properties:

  • Values: An IOrderedDictionary instance containing the non-key values in the new row.

  • AffectedRows: The number of rows that were deleted.

  • KeepInInsertMode: A Boolean value that you can set to indicate whether the current row control should remain in insert mode or return to normal mode.

  • Exception: An Exception instance returned if the insert process fails. A reference to the actual exception that was raised by the database can be obtained from the InnerException property of this current exception.

  • ExceptionHandled: A Boolean value that you can set to True after handling any exception raised by the insert process to indicate that this exception should not be raised to the code that called this method.

ItemUpdating

Raised before the data source control bound to the DetailsView updates a row. Passes a DetailsViewUpdateEventArgs instance to the event handler, which exposes the following properties:

  • Cancel: A Boolean property that can be set to True to cancel the update operation.

  • CommandArgument: The value of the CommandArgument property of the button that raised the event.

  • Keys: An IOrderedDictionary instance containing the primary key values for the row.

  • NewValues: An IOrderedDictionary instance containing the non-key values that will be placed into the row.

  • OldValues: An IOrderedDictionary instance containing the non-key values currently in the row.

ItemUpdated

Raised after the data source control bound to the DetailsView has updated a row. Passes a DetailsViewUpdatedEventArgs instance to the event handler, which exposes the AffectedRows property indicating the number of rows affected by the update operation.

  • Keys: An IOrderedDictionary instance containing the primary key values for the row.

  • NewValues: An IOrderedDictionary instance containing the non-key values that will be placed into the row.

  • OldValues: An IOrderedDictionary instance containing the non-key values currently in the row.

  • AffectedRows: The number of rows that were updated.

  • KeepInEditMode: A Boolean value that you can set to indicate whether the current row control should remain in edit mode or return to normal mode.

  • Exception: An Exception instance returned if the update process fails. A reference to the actual exception that was raised by the database can be obtained from the InnerException property of this current exception.

  • ExceptionHandled: A Boolean value that you can set to True after handling any exception raised by the update process to indicate that this exception should not be raised to the code that called this method.

ModeChanging

Raised before the DetailsView changes from one mode to another (ReadOnly, Edit, or Insert). Passes a DetailsViewModeEventArgs instance to the event handler, which exposes the following properties:

  • Cancel: A Boolean property that can be set to True to prevent the control changing to the new mode.

  • CancelingEdit: A Boolean value that is True if the mode change was caused by the user clicking the Cancel button while in edit mode.

  • NewMode: The new mode as a value from the DetailsViewMode enumeration. The value can be changed to display a different mode.

ModeChanged

Raised after the DetailsView has changed from one mode to another (ReadOnly, Edit, or Insert). Passes a standard EventArgs instance to the event handler.



     Python   SQL   Java   php   Perl 
     game development   web development   internet   *nix   graphics   hardware 
     telecommunications   C++ 
     Flash   Active Directory   Windows