Master/Detail Editing - DetailsView
Record editing with a single DetailsView or FormView works fine for small database tables
requiring few pages to navigate. For large recordsets, though, it may be difficult to locate
particular records by paging through them sequentially. What is required is a table of contents
to quickly locate records of interest, and a form for editing those that are found. These
requirements are easily provided in a master/detail setup. In the following example, a GridView
presents an index to all records in the BooksDB.mdb database; a linked
DetailsView gives editing access to individual records.
Note that making actual changes to the BooksDB.mdb database is not
permitted in these tutorials; however, all other functions work as expected.
Book Master
| ID | Title |
|
DB111
| Oracle Database |
|
DB222
| Databases in Depth |
|
DB333
| Database Processing |
|
DB444
| Access Database Design |
|
DB555
| SQL Server 2005 |
|
GR111
| Adobe Photoshop CS2 |
|
GR222
| Learning Web Design |
|
GR333
| Macromedia Flash Professional |
|
GR444
| Digital Photographer Handbook |
|
GR555
| Creating Motion Graphics |
|
HW111
| How Computers Work |
|
HW222
| Upgrading and Repairing PCs |
|
Book Detail
| |
|
| ID: | DB111 |
| Type: |
Database
|
| Title: | Oracle Database |
| Author: | K. Loney |
| Description: |
Get thorough coverage of Oracle Database 10g from the most comprehensive reference available, published by Oracle Press. With in-depth details on all the new features, this powerhouse resource provides an overview of database architecture and Oracle Grid Computing technology, and covers SQL, SQL*Plus, PL/SQL, dynamic PL/SQL, object-oriented features, and Java programming in the Oracle environment. You'll also find valuable database administration and application development techniques, plus an alphabetical reference covering major Oracle commands, keywords, features, and functions, with cross-referencing of topics.
|
| Price: | $69.99 |
| Qty: | 10 |
| Sale: | |
Figure 9-24. Master/detail record editing.
Coding the GridView
Code for the master GridView and its AccessDataSource are shown below. A TemplateField
containing <asp:LinkButton> controls both displays
BookIDs and configures them as command links for selecting books.
The CommandName for the LinkButtons is "Select" to tie
BookIDs to the SelectCommand property of the AccessDataSource
for the DetailsView.
<asp:AccessDataSource id="MasterSource" Runat="Server"
DataFile="../Databases/BooksDB.mdb"
SelectCommand="SELECT BookID, BookTitle FROM Books ORDER BY BookID"/>
<asp:GridView id="GridView" DataSourceID="MasterSource" Runat="Server"
DataKeyNames="BookID"
AutoGenerateColumns="False"
Caption="<b>Book Master</b>"
CaptionAlign="Left"
AllowPaging="True"
PageSize="12"
SelectedIndex="0"
SelectedRowStyle-BackColor="#E9E9E9"
HeaderStyle-BackColor="#E0E0E0"
Style="float:left; margin-bottom:200px">
<Columns>
<asp:TemplateField
HeaderText="ID"
HeaderStyle-Width="40"
HeaderStyle-Font-Size="10pt"
ItemStyle-Font-Size="10pt">
<ItemTemplate>
<asp:LinkButton CommandName="Select" Runat="Server"
Text='<%# Eval("BookID") %>'/>
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField DataField="BookTitle"
HeaderText="Title"
HeaderStyle-Width="180"
HeaderStyle-Font-Size="10pt"
Itemstyle-Font-Size="10pt"/>
</Columns>
</asp:GridView>
Listing 9-38. Coding a master GridView.
Coding the DetailsView
The DetailsView employs an AccessDataSource whose SelectCommand is
linked to the GridView selection through its SelectParameters. The
GridView's SelectedValue becomes the @BookID
parameter for displaying the chosen record. A second AccessDataSource fills DropDownLists
of book types during updating and inserting operations.
<asp:AccessDataSource id="DetailsSource" Runat="Server"
DataFile="../Databases/BooksDB.mdb"
SelectCommand="SELECT * FROM Books WHERE BookID = @BookID"
InsertCommand="INSERT INTO Books (BookID, BookType, BookTitle, BookAuthor,
BoodDescription, BookPrice, BookQty, BookSale)
VALUES (@BookID, @BookType, @BookTitle, @BookAuthor,
@BoodDescription, @BookPrice, @BookQty, @BookSale)"
UpdateCommand="UPDATE Books SET BookType=@BookType, BookTitle=@BookTitle,
BookAuthor=@BookAuthor, BoodDescription=@BoodDescription,
BookPrice=@BookPrice, BookQty=@BookQty, BookSale=@BookSale
WHERE BookID=@BookID"
>
<SelectParameters>
<asp:ControlParameter ControlID="GridView" Name="BookID"
PropertyName="SelectedValue"/>
</SelectParameters>
</asp:AccessDataSource>
<asp:AccessDataSource id="TypeSource" Runat="Server"
DataFile="../Databases/BooksDB.mdb"
SelectCommand="SELECT DISTINCT BookType FROM Books ORDER BY BookType"/>
Listing 9-39. Linking a DetailsView to a master GridView via AccessDataSource parameters.
Code for the DetailsView is shown below. Editing buttons are supplied through a TemplateField
containing Button controls configured as command buttons. Also, a set of delete confirmation buttons
appears inside the DetailsView's ItemTemplate.
<asp:DetailsView id="DetailsView" Runat="Server"
DataSourceID="DetailsSource"
AutoGenerateRows="False"
DataKeyNames="BookID"
OnItemInserting="Validate_Insert_Data"
OnItemInserted="Display_Insert_Msg"
OnItemUpdating="Validate_Update_Data"
OnItemUpdated="Display_Update_Msg"
OnItemDeleting="Confirm_Delete"
OnItemCommand="Get_Command"
Caption="<b>Book Detail</b>"
CaptionAlign="Left"
BorderStyle="Outset"
BorderWidth="1"
CellPadding="3"
GridLines="None"
RowStyle-Font-Size="10pt"
RowStyle-VerticalAlign="Top">
<Fields>
<asp:TemplateField
HeaderStyle-BackColor="#E0E0E0"
HeaderStyle-Font-Bold="True"
HeaderStyle-HorizontalAlign="Right"
ItemStyle-VerticalAlign="Top"
ItemStyle-BackColor="#E0E0E0"
ItemStyle-ForeColor="#FF0000">
<ItemTemplate>
<asp:Button CommandName="Edit" Text="Edit" Runat="Server"
Font-Size="8pt" Width="45"/>
<asp:Button CommandName="New" Text="New" Runat="Server"
Font-Size="8pt" Width="45"/>
<asp:Button CommandName="Delete" Text="Delete" Runat="Server"
Font-Size="8pt" Width="45"/>
<asp:Label id="ConfirmDelete" Visible="False" EnableViewState="False"
Runat="Server">
<asp:Label Text="<br/>Delete this record? " ForeColor="Red"
EnableViewState="False" Runat="Server"/>
<asp:Button Text="Yes" CommandName="Yes" Runat="Server"
Font-Size="7pt" Width="30px"/>
<asp:Button Text="No" CommandName="No" Runat="Server"
Font-Size="7pt" Width="30px"/>
</asp:Label>
</ItemTemplate>
<EditItemTemplate>
<asp:Button CommandName="Update" Text="Update" Runat="Server"
Font-Size="8pt" Width="45"/>
<asp:Button CommandName="Cancel" Text="Cancel" Runat="Server"
Font-Size="8pt" Width="45"/>
</EditItemTemplate>
<InsertItemTemplate>
<asp:Button CommandName="Insert" Text="Insert" Runat="Server"
Font-Size="8pt" Width="45"/>
<asp:Button CommandName="Cancel" Text="Cancel" Runat="Server"
Font-Size="8pt" Width="45"/>
</InsertItemTemplate>
</asp:TemplateField>
<asp:BoundField ReadOnly="True"
DataField="BookID"
HeaderText="ID: "
HeaderStyle-BackColor="#E0E0E0"
HeaderStyle-Font-Bold="True"/>
<asp:TemplateField
HeaderText="Type: "
HeaderStyle-BackColor="#E0E0E0"
HeaderStyle-Font-Bold="True">
<ItemTemplate>
<asp:Label Text='<%# Eval("BookType") %>' Runat="Server"/>
</ItemTemplate>
<EditItemTemplate>
<asp:DropDownList id="EditType" Runat="Server"
DataSourceID="TypeSource"
DataTextField="BookType"
DataValueField="BookType"
SelectedValue='<%# Bind("BookType") %>'/>
</EditItemTemplate>
</asp:TemplateField>
<asp:BoundField
DataField="BookTitle"
HeaderText="Title: "
HeaderStyle-BackColor="#E0E0E0"
HeaderStyle-Font-Bold="True"/>
<asp:BoundField
DataField="BookAuthor"
HeaderText="Author: "
HeaderStyle-BackColor="#E0E0E0"
HeaderStyle-Font-Bold="True"/>
<asp:TemplateField
HeaderText="Description: "
HeaderStyle-BackColor="#E0E0E0"
HeaderStyle-Font-Bold="True">
<ItemTemplate>
<asp:Panel Width="210px" Height="75px" BorderWidth="1px"
ScrollBars="Auto" BorderColor="#C0C0C0" Runat="Server">
<asp:Label Font-Size="10pt" Runat="Server"
Text='<%# Eval("BookDescription") %>'/>
</asp:Panel>
</ItemTemplate>
<EditItemTemplate>
<asp:TextBox id="EditDescription"
Text='<%# Bind("BookDescription") %>' Runat="Server"
TextMode="MultiLine" Height="75px" Width="210px"
Font-Name="Arial" Font-Size="9pt"/>
</EditItemTemplate>
</asp:TemplateField>
<asp:BoundField
DataField="BookPrice"
HtmlEncode="False"
DataFormatString="{0:C}"
HeaderText="Price: "
HeaderStyle-BackColor="#E0E0E0"
HeaderStyle-Font-Bold="True"/>
<asp:BoundField
DataField="BookQty"
HtmlEncode="False"
DataFormatString="{0:D}"
HeaderText="Qty: "
HeaderStyle-BackColor="#E0E0E0"
HeaderStyle-Font-Bold="True"/>
<asp:CheckBoxField
DataField="BookSale"
HeaderText="Sale: "
HeaderStyle-BackColor="#E0E0E0"
HeaderStyle-Font-Bold="True"/>
</Fields>
</asp:DetailsView>
<asp:Label id="EditMSG" EnableViewState="False" ForeColor="Red"
Runat="Server"/>
Listing 9-40. Code for DetailsView to display records selected from GridView.
Bound fields are used for several data fields, for example the BookPrice
field. When this control is placed in edit or insert mode, a default textbox appears for
changing or adding the field. To have more control over the size and properties of this entry box,
you may wish to use a TemplateField instead, enclosing an
<asp:TextBox>. This gives you the option of sizing the textbox, formatting its
text, and including the MaxLength property to restrict the number of
characters typed. A BoundField is a convenient editing device, but it may not provide the
formatting, styling, and data-entry options you seek.
DetailsView Scripting
Scripting for the DetailsView uses similar techniques as before. Click events are trapped by
OnItemInserting, OnItemInserted,
OnItemUpdating, OnItemUpdated,
OnItemDeleting, and OnItemCommand handlers.
During inserting and updating, subprograms validate entered data; during deletion, confirmation
buttons are presented. All subprograms display appropriate messages about the current editing
status.
<SCRIPT Runat="Server">
Sub Validate_Insert_Data (Src As Object, Args As DetailsViewInsertEventArgs)
If Args.Values("BookID") = "" Then
Args.Cancel = True
EditMSG.Text = "• Missing BookID"
End If
If Args.Values("BookTitle") = "" Then
Args.Cancel = True
EditMSG.Text = "• Missing title"
End If
If Args.Values("BookAuthor") = "" Then
Args.Cancel = True
EditMSG.Text = "• Missing author"
End If
If Args.Values("BookDescription") = "" Then
Args.Cancel = True
EditMSG.Text = "• Missing description"
End If
If Not IsNumeric(Args.Values("BookPrice")) Then
Args.Cancel = True
EditMSG.Text = "• Price is not numeric"
Else
If Args.Values("BookPrice") < 0 _
OR Args.Values("BookPrice") > 200 Then
Args.Cancel = True
EditMSG.Text = "• Price is out of range"
End If
End If
If Not IsNumeric(Args.Values("BookQty")) Then
Args.Cancel = True
EditMSG.Text = "• Quantity is not numeric"
Else
If Args.Values("BookQty") < 0 Then
Args.Cancel = True
EditMSG.Text = "• Quantity is out of range"
End If
End If
End Sub
Sub Display_Insert_Msg (Src As Object, Args As DetailsViewInsertedEventArgs)
EditMSG.Text = "• Record " & Args.Values("BookID") & " added"
GridView.DataBind()
End Sub
Sub Validate_Update_Data (Src As Object, Args As DetailsViewUpdateEventArgs)
If Args.NewValues("BookTitle") = "" Then
Args.Cancel = True
EditMSG.Text = "• Missing title"
End If
If Args.NewValues("BookDescription") = "" Then
Args.Cancel = True
EditMSG.Text = "• Missing description"
End If
If Not IsNumeric(Args.NewValues("BookPrice")) Then
Args.Cancel = True
EditMSG.Text = "•Price is not numeric"
Else
If Args.NewValues("BookPrice") < 0 _
OR Args.NewValues("BookPrice") > 200 Then
Args.Cancel = True
EditMSG.Text = "• Price is out of range"
End If
End If
If Not IsNumeric(Args.NewValues("BookQty")) Then
Args.Cancel = True
EditMSG.Text = "•Quantity is not numeric"
Else
If Args.NewValues("BookQty") < 0 Then
Args.Cancel = True
EditMSG.Text = "• Quantity is out of range"
End If
End If
End Sub
Sub Display_Update_Msg (Src As Object, Args As DetailsViewUpdatedEventArgs)
EditMSG.Text = "• Record " & Args.Keys("BookID") & " updated"
End Sub
Sub Confirm_Delete (Src As Object, Args As DetailsViewDeleteEventArgs)
Args.Cancel = True
Dim ConfirmLabel As Label
ConfirmLabel = DetailsView.Rows(Args.RowIndex).FindControl("ConfirmDelete")
ConfirmLabel.Visible = True
ViewState("BookID") = Args.Keys("BookID")
End Sub
Sub Get_Command (Src As Object, Args As DetailsViewCommandEventArgs)
If Args.CommandName = "Yes" Then
DetailsSource.DeleteCommand = "DELETE FROM Books " & _
"WHERE BookID = '" & _
ViewState("BookID") & "'"
DetailsSource.Delete()
GridView.DataBind()
EditMSG.Text = "• Record " & ViewState("BookID") & " deleted"
End If
End Sub
</SCRIPT>
Listing 9-41. Script to validate and update records through master/detail GridView/DetailsView.
You will notice a slight difference in coding from previous scripts to locate the
ConfirmDelete Label containing "Yes" and "No" confirmation buttons.
In coding this technique for a previous FormView, the control's
FindControl("id") method is used. For a DetailsView, however, this
method's format is different as shown below.
Sub Confirm_Delete (Src As Object, Args As DetailsViewDeleteEventArgs)
Args.Cancel = True
Dim ConfirmLabel As Label
ConfirmLabel = DetailsView.Rows(Args.RowIndex).FindControl("ConfirmDelete")
ConfirmLabel.Visible = True
ViewState("BookID") = Args.Keys("BookID")
End Sub
Listing 9-42. Finding controls in the first row of a DetailsView.
Whereas a FormView contains a single Row object that is searched
for a control, a DetailsView contains multiple Rows,
one for each visible row of the control. These rows are indexed beginning with 0, and this
index is used to point to the particular row to search to find an enclosed control.
Arguments passed to subprograms when events occur on a row include the
RowIndex property for that row. In the current DetailsView, the confirmation buttons
and their container Label appear in the same row as the "Delete" button. Therefore, when this
button is clicked to call the Confirm_Delete subprogram, this subprogram's
Args.RowIndex property points to the same row containing the confirmation
Label. This row, then, is searched for the ConfirmDelete Label.
Incidentally, in this particular example, it is known in advance that the confirmation label
is on row 0. Therefore, this fixed index can be used to find the Label:
DetailsView.Rows(0).FindControl("ConfirmDelete")
Notice in the example GridView that when a new record is added or an existing record is deleted
that the GridView is bound again from its AccessDataSource: GridView.DataBind().
This re-binding ensures that the GridView correctly represents the changed contents of the
Books table after records are added and deleted.
A FormView can be easily substituted for the above DetailsView. The one from the previous
FormView editing tutorial can be used by linking it to the GridView. Slight script changes are
needed for subprogram arguments and for locating embedded controls. Still, it is nearly a matter
of swapping one control for another.