Editing Records - FormView
A FormView control can include editing features to add new records to a database, update existing
records, and delete existing records. These functions can be performed without scripting, or
scripts can be added for pre- or post-processing activities. In the following example, a FormView
includes "Edit," "New," and "Delete" buttons for editing books from the
BooksDB.mdb database.
Note that making actual changes to the BooksDB.mdb database is not
permitted in these tutorials; however, all other functions work as expected.
Figure 9-19. Editing with a FormView.
Coding the FormView
Code for the FormView and its AccessDataSources for the above example is shown below.
This code may appear more extensive than for a DetailsView with the same functionality.
However, much of the code pertains to formatting the forms inside XHTML tables. There still
remain an ItemTemplate, EditItemTemplate, and InsertItemTemplate as comparable templates
for arranging display and edit fields.
The FormView uses an AccessDataSource that includes three SQL statements. The
SelectCommand, InsertCommand, and
UpdateCommand statements are identical to those used previously to edit a selected
record in a DetailsView. You might notice a missing DeleteCommand.
In this example, record deletion is scripted rather than taking place automatically through
the AccessDataSource. This deletion process is described below. A second AccessDataSource
supplies values for DropDownLists of book types during updates and additions.
A embedded Cascading Style Sheet is included in the code. Use of the style sheet makes it
easier to consistently style the three separate tables in the ItemTemplate, EditItemTemplate,
and InsertItemTemplate.
<style type="text/css">
table#ItemTable th {font-size:11pt; text-align:left; vertical-align:top;
background-color:#E0E0E0}
table#ItemTable td {font-size:11pt; vertical-align:top}
table#EditTable th {font-size:11pt; text-align:left; vertical-align:top;
background-color:#E0E0E0}
table#EditTable td {font-size:11pt; vertical-align:top}
table#AddTable th {font-size:11pt; text-align:left; vertical-align:top;
background-color:#E0E0E0}
table#AddTable td {font-size:11pt; vertical-align:top}
.buttons {background-color:#E0E0E0}
</style>
<asp:AccessDataSource id="BookSource" Runat="Server"
DataFile="../Databases/BooksDB.mdb"
SelectCommand="SELECT * FROM Books ORDER BY BookID"
InsertCommand="INSERT INTO Books (BookID, BookType, BookTitle, BookAuthor,
BookDescription, BookPrice, BookQty, BookSale) VALUES
(@BookID, @BookType, @BookTitle, @BookAuthor,
BookDescription=@BookDescription, @BookPrice, @BookQty,
@BookSale)"
UpdateCommand="UPDATE Books SET BookType=@BookType, BookTitle=@BookTitle,
BookAuthor=@BookAuthor, BookDescription=@BookDescription,
BookPrice=@BookPrice, BookQty=@BookQty, BookSale=@BookSale
WHERE BookID=@BookID"
/>
<asp:AccessDataSource id="TypeSource" Runat="Server"
DataFile="../Databases/BooksDB.mdb"
SelectCommand="SELECT DISTINCT BookType FROM Books ORDER BY BookType"/>
<h3>Book Edit</h3>
<asp:Label id="EditMSG" Text=" " ForeColor="Red" Runat="Server"
EnableViewState="False"/>
<asp:Panel id="ConfirmDelete" Visible="False" EnableViewState="False"
Runat="Server">
<asp:Label Text="Delete this record? " ForeColor="Red" Runat="Server"/>
<asp:Button Text="Yes" OnClick="Delete_Record" Runat="Server"
Font-Size="7pt" Height="17px" Width="30px"/>
<asp:Button Text="No" OnClick="Cancel_Delete" Runat="Server"
Font-Size="7pt" Height="17px" Width="30px"/>
</asp:Panel>
<asp:FormView id="FormView" DataSourceID="BookSource" Runat="Server"
DataKeyNames="BookID"
OnItemInserting="Validate_Insert_Data"
OnItemInserted="Display_Insert_Msg"
OnItemUpdating="Validate_Update_Data"
OnItemUpdated="Display_Update_Msg"
OnItemDeleting="Confirm_Delete"
AllowPaging="True"
GridLines="Both">
<ItemTemplate>
<table id="ItemTable" border="0" cellpadding="3" cellspacing="0">
<tr>
<th></th>
<td class="buttons">
<asp:LinkButton CommandName="Edit" Text="Edit" Runat="Server"/>
<asp:LinkButton CommandName="New" Text="New" Runat="Server"/>
<asp:LinkButton CommandName="Delete" Text="Delete" Runat="Server"/>
</td>
</tr>
<tr>
<th>ID</th>
<td><asp:Label Text='<%# Eval("BookID") %>' Runat="Server"/></td>
</tr>
<tr>
<th>Type</th>
<td><asp:Label Text='<%# Eval("BookType") %>' Runat="Server"/></td>
</tr>
<tr>
<th>Title</th>
<td><asp:Label Text='<%# Eval("BookTitle") %>' Runat="Server"/></td>
</tr>
<tr>
<th>Author</th>
<td><asp:Label Text='<%# Eval("BookAuthor") %>' Runat="Server"/></td>
</tr>
<tr>
<th>Description</th>
<td><asp:Panel Width="350px" Height="95px" BorderWidth="1px"
BorderColor="#C0C0C0" ScrollBars="Auto" Runat="Server">
<asp:Label Text='<%# Eval("BookDescription") %>' Font-Size="10pt"
Runat="Server"/>
</asp:Panel></td>
</tr>
<tr>
<th>Price</th>
<td><asp:Label Text='<%# String.Format("{0:C}", Eval("BookPrice")) %>'
Runat="Server"/></td>
</tr>
<tr>
<th>Qty</th>
<td><asp:Label Text='<%# String.Format("{0:D}", Eval("BookQty")) %>'
Runat="Server"/></td>
</tr>
<tr>
<th>Sale</th>
<td><asp:CheckBox Checked='<%# Eval("BookSale") %>' Enabled="False"
Runat="Server"/></td>
</tr>
</table>
</ItemTemplate>
<EditItemTemplate>
<table id="EditTable" border="0" cellpadding="3" cellspacing="0">
<tr>
<th></th>
<td class="buttons">
<asp:LinkButton CommandName="Update" Text="Update" Runat="Server"/>
<asp:LinkButton CommandName="Cancel" Text="Cancel" Runat="Server"/>
</td>
</tr>
<tr>
<th>ID</th>
<td><asp:Label Text='<%# Eval("BookID") %>' Runat="Server"/></td>
</tr>
<tr>
<th>Type</th>
<td><asp:DropDownList id="BookType" Runat="Server"
DataSourceID="TypeSource"
DataTextField="BookType"
DataValueField="BookType"
SelectedValue='<%# Bind("BookType") %>'/></td>
</tr>
<tr>
<th>Title</th>
<td><asp:TextBox id="EditTitle" Runat="Server"
Text='<%# Bind("BookTitle") %>'/></td>
</tr>
<tr>
<th>Author</th>
<td><asp:TextBox id="EditAuthor" Runat="Server"
Text='<%# Bind("BookAuthor") %>'/></td>
</tr>
<tr>
<th>Description</th>
<td><asp:TextBox id="EditDescription" Runat="Server
Text='<%# Bind("BookDescription") %>'"
TextMode="MultiLine" Height="95" Width="350px"
Font-Name="Arial" Font-Size="9pt"/></td>
</tr>
<tr>
<th>Price</th>
<td><asp:TextBox id="EditPrice" Runat="Server"
Text='<%# Bind("BookPrice") %>'
Width="50px"/></td>
</tr>
<tr>
<th>Quantity</th>
<td><asp:TextBox id="EditQty" Runat="Server"
Text='<%# Bind("BookQty") %>'
Width="50px"/></td>
</tr>
<tr>
<th>Sale</th>
<td><asp:CheckBox id="EditSale" Runat="Server"
Checked='<%# Bind("BookSale") %>'/></td>
</tr>
</table>
</EditItemTemplate>
<InsertItemTemplate>
<table id="AddTable" border="0" cellpadding="3" cellspacing="0">
<tr>
<th></th>
<td class="buttons">
<asp:LinkButton CommandName="Insert" Text="Insert" Runat="Server"/>
<asp:LinkButton CommandName="Cancel" Text="Cancel" Runat="Server"/>
</td>
</tr>
<tr>
<th>ID</th>
<td><asp:TextBox id="AddBookID" Runat="Server"
Text='<%# Bind("BookID") %>'/></td>
</tr>
<tr>
<th>Type</th>
<td><asp:DropDownList id="AddType" Runat="Server"
DataSourceID="TypeSource"
DataTextField="BookType"
DataValueField="BookType"
SelectedValue='<%# Bind("BookType") %>'/></td>
</tr>
<tr>
<th>Title</th>
<td><asp:TextBox id="AddTitle" Runat="Server"
Text='<%# Bind("BookTitle") %>'/></td>
</tr>
<tr>
<th>Author</th>
<td><asp:TextBox id="AddAuthor" Runat="Server"
Text='<%# Bind("BookAuthor") %>'/></td>
</tr>
<tr>
<th>Description</th>
<td><asp:TextBox id="AddDescription" Runat="Server"
Text='<%# Bind("BookDescription") %>'
TextMode="MultiLine" Rows="5" Width="350px"
Font-Name="Arial" Font-Size="9pt"/></td>
</tr>
<tr>
<th>Price</th>
<td><asp:TextBox id="AddPrice" Runat="Server"
Text='<%# Bind("BookPrice") %>'/></td>
</tr>
<tr>
<th>Qty</th>
<td><asp:TextBox id="AddQty" Runat="Server"
Text='<%# Bind("BookQty") %>'/></td>
</tr>
<tr>
<th>Sale</th>
<td><asp:CheckBox id="AddSale" Runat="Server"
Checked='<%# Bind("BookSale") %>'/></td>
</tr>
</table>
</InsertItemTemplate>
</asp:FormView>
Listing 9-24. Code for FormView with editing.
The FormView requires three templates, one for viewing a record (ItemTemplate), one for
updates (EditItemTemplate), and one for additions (InsertItemTemplate). All three templates
include <table> tags to arrange labels and controls for formatted
display. All templates must include buttons to trigger editing activity. LinkButtons are used in
this example. These buttons must include proper CommandNames for editing
(Edit, New, and Delete),
for updating (Update and Cancel), and for
inserting (Insert and Cancel). Data display
controls for updating and inserting records must use editable controls along with
Bind() expressions so that changed or inserted values can be posted
back to the database.
Like the GridView and DetailsView, a FormView immediately deletes a record when the "Delete"
button is clicked. For this example, a confirmation step is added. When the button is clicked,
a pair of "Yes" and "No" buttons appear to confirm or cancel deletion. These buttons are coded
inside a Panel control that is initially hidden.
<asp:Panel id="ConfirmDelete" Visible="False" EnableViewState="False"
Runat="Server">
<asp:Label Text="Delete this record? " ForeColor="Red" Runat="Server"/>
<asp:Button Text="Yes" OnClick="Delete_Record" Runat="Server"
Font-Size="7pt" Height="17px" Width="30px"/>
<asp:Button Text="No" OnClick="Cancel_Delete" Runat="Server"
Font-Size="7pt" Height="17px" Width="30px"/>
</asp:Panel>
Listing 9-25. Code for delete confirmation display for FormView.
This Panel is not part of the FormView. It appears outside and immediately preceding the FormView.
It is made visible by a Confirm_Delete subprogram that is called on the
ItemDeleting event that occurs when the "Delete" button is clicked. This subprogram is described below.
FormView Events and Event Handlers
"Insert," "Update," and "Delete" buttons for the FormView have events associated with them for
calling subprograms to intercept these processes. These events, their event handlers, and
arguments of called subprograms are listed below. Except for argument names, these events
and handlers are the same as those associated with a DetailsView.
| Event |
Event Handler |
Signature |
Description |
| ItemInserting |
OnItemInserting |
FormViewInsertEventArgs |
A new record is being added to the data source but has not yet been written. |
| ItemInserted |
OnItemInserted |
FormViewInsertedEventArgs |
A new record has been written to the data source. |
| ItemUpdating |
OnItemUpdating |
FormViewUpdateEventArgs |
A record is being updated but has not yet been rewritten to the data source. |
| ItemUpdated |
OnItemUpdated |
FormViewUpdatedEventArgs |
An updated record has been rewritten to the data source. |
| ItemDeleting |
OnItemDeleting |
FormViewDeleteEventArgs |
A record is being deleted from the data source but has not yet been deleted. |
| ItemDeleted |
OnItemDeleted |
FormViewDeletedEventArgs |
A record has been deleted from the data source. |
Figure 9-20. FormView event handlers and subprogram argument signatures.
As in the case with the DetailsView, subprograms called by these event handlers expose event
properties that can be investigated. These properties are listed below and are identical to those
exposed through DetailsView events.
Figure 9-21. General formats for referencing FormView event properties.
FormView Event Scripting
Scripts for the OnInserting, OnInserted, OnUpdating, OnUpdated, and OnDeleting events trapped
for the example FormView are shown below. Except for added functionality for the OnDeleting
event, the remaining subprograms are identical to those used with the previous DetailsView.
<SCRIPT Runat="Server">
'-- OnItemInserting --
Sub Validate_Insert_Data (Src As Object, Args As FormViewInsertEventArgs)
If Args.Values("BookID") = "" Then
Args.Cancel = True
EditMSG.Text = "-- Missing BookID. Record not added."
End If
If Not IsNumeric(Args.Values("BookPrice")) Then
Args.Cancel = True
EditMSG.Text = "-- Book Price is not numeric. Record not added."
End If
If Not IsNumeric(Args.Values("BookQty")) Then
Args.Cancel = True
EditMSG.Text = "-- Book Quantity is not numeric. Record not added"
End If
If Args.Cancel = False Then
If Args.Values("BookPrice") < 0 _
OR Args.Values("BookPrice") > 200 Then
Args.Cancel = True
EditMSG.Text = "-- Book Price out of range. Record not added"
End If
End If
If Args.Cancel = False Then
If Args.Values("BookQty") < 0 Then
Args.Cancel = True
EditMSG.Text = "-- Book Quantity out of range. Record not added"
End If
End If
End Sub
'-- OnItemInserted --
Sub Display_Insert_Msg (Src As Object, Args As FormViewInsertedEventArgs)
EditMSG.Text = " Record " & Args.Values("BookID") & " added"
End Sub
'-- OnItemUpdating --
Sub Validate_Update_Data (Src As Object, Args As FormViewUpdateEventArgs)
If Not IsNumeric(Args.NewValues("BookPrice")) Then
Args.Cancel = True
EditMSG.Text = "-- Book Price is not numeric. Record not updated."
End If
If Not IsNumeric(Args.NewValues("BookQty")) Then
Args.Cancel = True
EditMSG.Text = "-- Book Quantity is not numeric. Record not updated"
End If
If Args.Cancel = False Then
If Args.NewValues("BookPrice") < 0 Then
Args.Cancel = True
EditMSG.Text = "-- Book Price out of range. Record not updated"
End If
End If
If Args.Cancel = False Then
If Args.NewValues("BookQty") < 0 _
OR Args.NewValues("BookPrice") > 200 Then
Args.Cancel = True
EditMSG.Text = "-- Book Quantity out of range. Record not updated"
End If
End If
End Sub
'-- OnItemUpdated --
Sub Display_Update_Msg (Src As Object, Args As FormViewUpdatedEventArgs)
EditMSG.Text = " Record " & Args.Keys("BookID") & " updated"
End Sub
'-- OnItemDeleting --
Sub Confirm_Delete (Src As Object, Args As FormViewDeleteEventArgs)
Args.Cancel = True
ConfirmDelete.Visible = True
EditMSG.Visible = False
ViewState("BookID") = Args.Keys("BookID")
End Sub
Sub Delete_Record (Src As Object, Args As EventArgs)
BookSource.DeleteCommand = "DELETE FROM Books " & _
"WHERE BookID = '" & ViewState("BookID") & "'"
BookSource.Delete()
EditMSG.Text = " Record " & ViewState("BookID") & " deleted"
End Sub
Sub Cancel_Delete (Src As Object, Args As EventArgs)
ConfirmDelete.Visible = False
End Sub
</SCRIPT>
Listing 9-26. Scripts for editing events of FormView.
When a new record's "Insert" button is clicked and an ItemInserting event is raised, the
Validate_Insert_Data subprogram is called. The record must be supplied
with a BookID value since this is the key for the record. Also,
numeric fields must contain numeric data. If any field fails a validation test, inserting is
cancelled. On an ItemInserted event, the Display_Insert_Msg subprogram
is called and a record-added message is displayed.
Editing for the ItemUpdating event is similar except that no test is made for a valid
BookID field since this field is not available for editing.
On an ItemUpdated event, a record-updated message is displayed.
Delete Confirmation
When the "Delete" button is clicked and an ItemDeleting event occurs, the
Confirm_Delete subprogram is called to immediately cancel the delete event and to make
the ConfirmDelete Panel visible with its confirmation buttons. Since
the delete event is cancelled, the Args.Keys("BookID") reference
to the BookID key for this record is lost to subsequent subprograms
to delete the record should it be confirmed. Therefore, this key is saved to a View State
variable, ViewState("BookID"), for subsequent retrieval.
Sub Confirm_Delete (Src As Object, Args As FormViewDeleteEventArgs)
Args.Cancel = True
ConfirmDelete.Visible = True
EditMSG.Visible = False
ViewState("BookID") = Args.Keys("BookID")
End Sub
Listing 9-27. Code to activate delete confirmation Panel of FormView.
This is the case if the "Yes" button is clicked and the Delete_Record
subprogram is called. This subprogram composes a DELETE statement,
using the saved ViewState("BookID") to identify the key of the
record to be deleted. The statement is assigned to the DeleteCommand
property of AccessDataSource for the FormView, and its Delete()
method is called to delete the record. This scripted delete operation is the reason a
DeleteCommand statement is not needed in the AccessDataSource.
Sub Delete_Record (Src As Object, Args As EventArgs)
BookSource.DeleteCommand = "DELETE FROM Books " & _
"WHERE BookID = '" & ViewState("BookID") & "'"
BookSource.Delete()
EditMSG.Text = " Record " & ViewState("BookID") & " deleted"
End Sub
Listing 9-28. Script to delete a FormView record.
If, on the other hand, the "No" confirmation button is clicked, no action is taken on the
record. Instead, the Cancel_Delete subprogram is called simply to hide the
confirmation Panel.
Sub Cancel_Delete (Src As Object, Args As EventArgs)
ConfirmDelete.Visible = False
End Sub
Listing 9-29. Script to cancel deletion of a FormView record.
This method of coding the FormView with its AccessDataSources and scripts can be applied to
a DetailsView or GridView to supply record-deletion confirmation in these controls.
Using Command Events
In the above FormView the delete confirmation buttons appear outside the FormView itself.
As a visual option you may wish to incorporate the "Yes" and "No" buttons inside the control as you
can see by clicking the "Delete" button in the following FormView.
Figure 9-22. Editing with a FormView.
Coding for the FormView is similar to the previous example. One difference is that the
LinkButton controls are coded here as Button controls. A second difference is in the section of the
ItemTemplate where confirmation buttons are included along with the "Edit," "New," and
"Delete" buttons. In the previous example, these "Yes" and "No" buttons are enclosed inside a
Panel to control their visibility. Here they are enclosed inside a Label control. A
Label is used so the confirmation buttons appear on the same line as the edit buttons (a Panel
control causes a line break). As before, the buttons are initially hidden since the
ConfirmDelete Label that contains them is hidden.
<asp:FormView id="FormView" DataSourceID="BookSource" Runat="Server"
...
OnItemDeleting="Confirm_Delete"
OnItemCommand="Get_Command"
>
<ItemTemplate>
<table id="ItemTable" border="0" cellpadding="3" cellspacing="0">
<tr>
<th></th>
<td class="buttons">
<asp:Button CommandName="Edit" Text="Edit" Font-Size="9pt" Width="50"
Runat="Server"/>
<asp:Button CommandName="New" Text="New" Font-Size="9pt" Width="50"
Runat="Server"/>
<asp:Button CommandName="Delete" Text="Delete" Font-Size="9pt"
Width="50" Runat="Server"/>
<asp:Label id="ConfirmDelete" Visible="False" EnableViewState="False"
Runat="Server">
<asp:Label Text="Delete this record? " ForeColor="Red"
Runat="Server"/>
<asp:Button Text="Yes" CommandName="Yes" Font-Size="8pt" Width="30px"
Runat="Server"/>
<asp:Button Text="No" CommandName="No" Font-Size="8pt" Width="30px"
Runat="Server"/>
</asp:Label>
</td>
</tr>
...
<EditItemTemplate>
<table id="EditTable" border="0" cellpadding="3" cellspacing="0">
<tr>
<th></th>
<td class="buttons">
<asp:Button CommandName="Update" Text="Update" Font-Size="9pt"
Width="50" Runat="Server"/>
<asp:Button CommandName="Cancel" Text="Cancel" Font-Size="9pt"
Width="50" Runat="Server"/>
</td>
</tr>
<tr>
...
<InsertItemTemplate>
<table id="AddTable" border="0" cellpadding="3" cellspacing="0">
<tr>
<th></th>
<td class="buttons">
<asp:Button CommandName="Insert" Text="Insert" Font-Size="9pt"
Width="50" Runat="Server"/>
<asp:Button CommandName="Cancel" Text="Cancel" Font-Size="9pt"
Width="50" Runat="Server"/>
</td>
</tr>
...
</asp:FormView>
Listing 9-30. Coding a FormView with command buttons.
These command names replace the subprogram calls of the previous example. Subprograms
Confirm_Delete, Delete_Record, and
Cancel_Delete are no longer required, replaced by two new subprograms
described below.
First, the confirmation Label must be "found" in the FormView. The FormView's
FindControl() method locates a control by its id
value, after which it is assigned to a variable of the same type (a Label
type in this instance). Once this control has been found and assigned to a variable, its
Visible property is set to True, thereby
revealing the "Yes" and "No" confirmation buttons. As before, the key of the currently displayed
record is saved to ViewState("BookID") for deletion of this record,
if requested, in a different subprogram.
When either of the two confirmation buttons is clicked, an ItemCommand event is raised and
the Get_Command subprogram is called by the FormView's
OnItemCommand event handler. This subprogram has the argument
FormViewCommandEventArgs and is shown below.
Action needs to be taken only on a click of the "Yes" button to delete the associated record.
Therefore, if the command name passed to the subprogram (Args.CommandName)
is "Yes," then an SQL DELETE statement is issued
through the FormView's AccessDataSource. The record identified in
ViewState("BookID") is deleted. If the "No" button is clicked (which calls this same
subprogram), no action is taken. In either case, the confirmation buttons are hidden since their
container Label is coded with EnableViewState="False" to revert to hidden
status any time a page post-back occurs.