Deleting a Row
Deleting a row is fairly straightforward except for paging errors. The DataGrid
has built in support for deletions with the OnDeleteCommand property. You simply
edit the DataGrid tags and set the delete event handler using the OnDeleteCommand
property. The DataGrid will register your event handler. You then must add
your delete event handler to the WebForm1.aspx.cs file. You need to implement
special logic if the deleted row is the only row on the last page.
Register the Delete Event Handler
If you look at the file WebForm1.aspx in the HTML view you will see where the
OnDeleteCommand property is set to "DataGrid_Delete". The DataGrid
will use this property to register the delete event handler:
<asp:datagrid id=DataGrid1 style="Z-INDEX: 101; LEFT: 23px; POSITION:
absolute; TOP: 221px" runat="server"
DataKeyField="au_id" DataSource="<%# view %>" Height="270px" Width="679px"
OnUpdateCommand="DataGrid1_Update" OnCancelCommand="DataGrid1_Cancel" OnEditCommand="DataGrid1_Edit"
OnDeleteCommand="DataGrid1_Delete" BorderColor="Blue" OnItemCommand="Item_Click" AllowSorting="True"
OnSortCommand="DataGrid1_Sort"
AllowPaging="True" OnPageIndexChanged="DataGrid1_Page" BackColor="#C0FFFF">
Add a Delete Button to the DataGrid
Using the Design view, you can add a "Delete" button to the DataGrid
by right clicking on the DataGrid and choosing the property builder. Under "Columns",
expand the "Available Column" "Button Column". You will
see a "Delete" button that can be added to the "Selected Columns".
Don't forget to "Apply" any changes.
Add the Event Handler to WebForm1.aspx.cs
Finally, you need to add the Delete event handler with the proper signature
to the WebForm1.asp.cs file. Here is the latest implementation of DataGrid1_Delete
(code in red is new):
protected void DataGrid1_Delete(Object sender, DataGridCommandEventArgs
e)
{
string key = DataGrid1.DataKeys[e.Item.ItemIndex].ToString();
string debug= "No errors.";
// Updates the dataset table
try
{
DataRow dr= dataSet11.authors.FindByau_id(key);
dr.Delete();
sqlDataAdapter1.Update(dataSet11);
}
catch (Exception exc)
{
sqlDataAdapter1.Fill(dataSet11); //if Update fails,
refresh dataset
debug= exc.Message;
}
// check for invalid page index
ResetPageIndex(DataGrid1,view);
DataGrid1.EditItemIndex = -1;
DataGrid1.DataBind();
textBoxMessage.Text= debug;
}
Since the data in the DataGrid may not be synchronized with the data in the
DataSet, you must find the proper row in the DataSet using the primary key
of the selected row. You can retrieve the selected row's primary key by calling:
string key = DataGrid1.DataKeys[e.Item.ItemIndex].ToString();
This works only if you have declared the primary key field in the DataGrid
by setting the "DataKeyField" to "au_id". Once you have
the primary key of the selected row in the DataGrid, you can find the corresponding
row in the DataSet by calling:
DataRow dr= dataSet11.authors.FindByau_id(key);
You can now delete the selected row in the DataSet by calling:
dr.Delete();
At this point the row is marked for deletion in the DataSet, but the row
still exists in the database. You must call Update() to commit the changes
to the
database:
sqlDataAdapter1.Update(dataSet11);
To avoid paging to a non-existent page, you need to implement some special
logic to decrement the page index if the page index is invalid:
// check for invalid page index
ResetPageIndex(DataGrid1,view);
Here again is the ResetPageIndex function:
// ResetPageIndex resets invalid page index to last page
// ASSERT grid and view NOT NULL
protected void ResetPageIndex(DataGrid grid, DataView view)
{
// check for invalid page index
if ((grid.CurrentPageIndex != 0) && (((grid.CurrentPageIndex)*grid.PageSize)>=
view.Count))
{
// invalid so leave at last page
if ((view.Count % grid.PageSize)== 0)
{ // ends on page border
grid.CurrentPageIndex= (view.Count/grid.PageSize)-1;
}
else // partial page
{
grid.CurrentPageIndex= (view.Count/grid.PageSize);
}
}
}
You should really call this function in _any_ post back that calls Fill and
DataBind.
Finally, you call DataBind() to refresh the DataGrid which should now reflect
any successful deletions.
DataGrid1.EditItemIndex = -1;
DataGrid1.DataBind();
If the deletion fails, the exceptions will be caught and the error message
sent back to the user in a multi-line text box.
Add Client Side JavaScript Support
As a final step, add client side JavaScript support, popping up a MessageBox
to confirm a deletion. If the user cancels the MessageBox, the post back
should not be executed. Unfortunately, there appears to be a bug in the
post back event model when in the Edit mode. In Edit mode, the delete event
handler
is called even if the user cancels the MessageBox! As a workaround you
must disable deletion if the selected row is in Edit mode. I have modified
the
DataGrid in the sample project so that the delete column is the first column
in the grid in the Design View. This was done using the Property Builder:
DataGrid --> Right Click --> Property Builder --> Columns --> Selected
Columns --> Delete --> Up Arrow --> Apply
As a first step, add the OnItemCreated event handler (in red) to the asp:datagrid
tag:
<asp:datagrid id=DataGrid1 runat="server" DataKeyField="au_id" DataSource="<%#
view %>"
OnUpdateCommand="DataGrid1_Update" OnCancelCommand="DataGrid1_Cancel"
OnEditCommand="DataGrid1_Edit" OnDeleteCommand="DataGrid1_Delete"
BorderColor="Blue" OnItemCommand="Item_Click" AllowSorting="True"
OnSortCommand="DataGrid1_Sort" AllowPaging="True" OnItemCreated= "DataGrid1_ItemCreated"
OnPageIndexChanged="DataGrid1_Page" BackColor="#C0FFFF">
You can now dynamically add client side JavaScript code to the first column
in the DataGrid. This is done in your DataGrid1_ItemCreated event handler.
The following is taken from Jeff Prosise's article Wicked Code in MSDN Magazine
(August, 2002). Note the interesting cast to the base class WebControl, not
to a LinkButton. This cast should work even if you change the column type
to a Button.
// this method FAILS in edit mode due to post back bug which
calls
// the delete event handler in edit mode even on cancel!
protected void DataGrid1_ItemCreated(Object sender, DataGridItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType ==
ListItemType.AlternatingItem)
{
WebControl button = (WebControl) e.Item.Cells[0].Controls[0];
button.Attributes.Add("onclick", "return confirm
(\"Really? Delete? \");");
}
}
Here is the actual HTML generated by IIS:
<td><a onclick="return confirm ('Really? Delete?
');"
href="javascript:__doPostBack('DataGrid1:_ctl3:_ctl0','')">Delete</a></td>
Now you need to modify the delete event handler to trap the delete event
if the selected row is in edit mode. The added code is in red. This code
post
a warning to the user, and immediately returns from the delete event handler.
// adds workaround for javascript post back bug by disabling
// the delete event handler if the selected row is in edit mode
protected void DataGrid1_Delete(Object sender, DataGridCommandEventArgs e)
{
if (DataGrid1.EditItemIndex == e.Item.ItemIndex)
{
ResetPageIndex(DataGrid1,view);
textBoxMessage.Text= "WARNING: Unable to delete record
in edit mode!\r
Please Cancel Edit Mode.";
return;
}
string key = DataGrid1.DataKeys[e.Item.ItemIndex].ToString();
string debug= "No errors.";
// Updates the dataset table
try
{
DataRow dr= dataSet11.authors.FindByau_id(key);
dr.Delete();
sqlDataAdapter1.Update(dataSet11);
}
catch (Exception exc)
{
sqlDataAdapter1.Fill(dataSet11); //if Update fails,
refresh dataset
debug= exc.Message;
}
// check for invalid page index
ResetPageIndex(DataGrid1,view);
DataGrid1.EditItemIndex = -1;
DataGrid1.DataBind();
textBoxMessage.Text= debug;
}