.<1> - }
Features
The GridViewExtender
class provides the following features.
- Client-side confirmation (via a JavaScript
confirm
dialog) before deleting a row from the grid. - Callback functions may be specified for the data binding, saving, and deleting functions. These are specified when the class is instantiated. This allows the developer to focus on the data-processing and business logic of the grid, rather than the proper "wiring" of the event handlers.
- Automatic display of the correct action buttons depending on whether a row is being editted or not, the same as how the default action buttons are displayed.
Consuming the Class in Your ASPX Page
ASPX Markup Code
The following markup code is only a partial listing. You must add your own columns for the data fields. The key element here is the the <asp:TemplateField>
that contains the action buttons, because the GridViewExtender
class expects it to be coded this way.
- You can change the order of the buttons, or even move them to different columns.
- You can change the
ImageUrl
for each button. - If you want to use
LinkButton
s or Button
s instead of ImageButton
s, you must change the code in the GridViewExtender
class accordingly. Search for "ImageButton" and replace it with either "LinkButton" or "Button" according to the button style you decide to use.
<asp:GridView runat="server" ID="uxGridView" AutoGenerateColumns="false"
CellPadding="3" CellSpacing="0" DataKeyNames="ID">
<EmptyDataTemplate>
No records match your search criteria.
</EmptyDataTemplate>
<Columns>
<%-- TODO: Add columns to this GridView --%>
<asp:TemplateField>
<HeaderTemplate>Action</HeaderTemplate>
<ItemTemplate>
<asp:ImageButton runat="server" ID="uxEditButton"
CommandName="Edit" ImageUrl="~/images/Pencil.png"
ToolTip="Edit"
/>
<asp:ImageButton runat="server" ID="uxDeleteButton"
CommandName="Delete" ImageUrl="~/images/Delete.png"
ToolTip="Delete"
/>
<%-- TODO: Specify ValidationGroup for the Save button --%>
<asp:ImageButton runat="server" ID="uxSaveButton"
CommandName="Update" ImageUrl="~/images/Save.png"
ToolTip="Save Changes"
/>
<asp:ImageButton runat="server" ID="uxCancelButton"
CommandName="Cancel" ImageUrl="~/images/StopSign.png"
ToolTip="Discard Changes"
/>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
<asp:Button runat="server" ID="uxAddNewButton" Text="Add New" />
Declare a Private Variable
C#
private GridViewExtender _gridViewExt;
Visual Basic
Private _gridViewExt as GridViewExtender
Write Callback Function to Retrieve Data
This will be the Requery Handler procedure used when you instantiate the GridViewExtender
class. Its purpose is to retrieve data to be displayed in the grid. Make sure you use the function signature shown in the example.
C#
private DataTable QueryData()
{
int id = Session["ID"];
DataTable t = db.GetRecords(id);
return t;
}
Visual Basic
Private Function QueryData() As DataTable
Dim id as Integer = Session("ID")
Dim t as DataTable = db.GetRecords(id)
Return t
End Function
Write Callback Function to Save Changes to a Row
This will be the Update Handler procedure used when you instantiate the GridViewExtender
class. Its purpose is to save the user's changes to the edited row. Make sure you use the function signature shown in the example.
C#
private void UpdateData(DataKey rowKey, GridViewRow gvRow)
{
if (Page.IsValid)
{
int id = int.Parse(rowKey["ID"].ToString());
string description = (gvRow.FindControl("uxDescriptionTextBox") as TextBox).Text;
db.SaveData(id, description);
}
}
Visual Basic
Private Sub UpdateData(ByVal rowKey as DataKey, ByVal gvRow as GridViewRow)
If Page.IsValid Then
Dim id as Integer = Convert.ToInt32(rowKey("ID"))
Dim description As String = CType(gvRow.FindControl("uxDescriptionTextBox"), TextBox).Text
db.SaveData(id, description)
End If
End Sub
Write Callback Function to Delete a Row
This will be the Delete Handler procedure used when you instantiate the GridViewExtender
class. Its purpose is to delete the selected row. Make sure you use the function signature shown in the example.
C#
private void DeleteData(DataKey rowKey)
{
int id = int.Parse(rowKey["ID"].ToString());
db.DeleteData(id);
}
Visual Basic
Private Sub DeleteData(ByVal rowKey as DataKey)
Dim id as Integer = Convert.ToInt32(rowKey("ID"))
db.DeleteData(id)
End Sub
Instantiate the Class
This should be done unconditionally (i.e., NOT inside the If Not Page.IsPostBack
block).
C#
_gridViewExt = new GridViewExtender(uxGridView, "Description",
New EmptyDelegate(AddressOf QueryData),
New DataKeyDelegate(AddressOf DeleteData),
New GridViewRowDelegate(AddressOf UpdateData));
Visual Basic
_gridViewExt = new GridViewExtender(uxGridView, "Description", _
New EmptyDelegate(AddressOf QueryData), _
New DataKeyDelegate(AddressOf DeleteData), _
New GridViewRowDelegate(AddressOf UpdateData))
Querying Data
This should be done conditionally (i.e., inside the If Not Page.IsPostBack
block).
_gridViewExt.Requery()
Source Code
Sample Code-Behind
C#
private GridViewExtender _gridViewExt;
protected void Page_Load(object sender, EventArgs e)
{
_gridViewExt = New GridViewExtender(uxGridView, "Description",
New EmptyDelegate(AddressOf QueryData),
New DataKeyDelegate(AddressOf DeleteData),
New GridViewRowDelegate(AddressOf UpdateData));
if (!Page.IsPostBack)
_gridViewExt.Requery();
}
private DataTable QueryData()
{
//TODO: Code the QueryData procedure
//int id = Session["ID"];
//DataTable t = db.GetRecords(id);
//return t;
}
private void UpdateData(DataKey rowKey, GridViewRow gvRow)
{
//TODO: Code the UpdateData procedure
if (Page.IsValid)
{
//int id = int.Parse(rowKey["ID"]);
//string description = (gvRow.FindControl("uxDescriptionTextBox") As TextBox).Text;
//db.SaveData(id, description);
}
}
private void DeleteData(DataKey rowKey)
{
//TODO: Code the DeleteData procedure
//int id = int.Parse(rowKey["ID"]);
//db.DeleteData(id);
}
private void uxAddNewButton_Click(object sender, EventArgs e)
{
_gridViewExt.AddNew();
}
Visual Basic
Private _gridViewExt As GridViewExtender
Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Load
_gridViewExt = New GridViewExtender(uxGridView, "Description", _
New EmptyDelegate(AddressOf QueryData), _
New DataKeyDelegate(AddressOf DeleteData), _
New GridViewRowDelegate(AddressOf UpdateData))
If Not Page.IsPostBack Then
_gridViewExt.Requery()
End If
End Sub
Private Function QueryData() As DataTable
'TODO: Code the QueryData procedure
'Dim id as Integer = Session("ID")
'Dim t as DataTable = db.GetRecords(id)
'Return t
End Function
Private Sub UpdateData(ByVal rowKey as DataKey, ByVal gvRow as GridViewRow)
'TODO: Code the UpdateData procedure
If Page.IsValid Then
'Dim id as Integer = Convert.ToInt32(rowKey("ID"))
'Dim description As String = CType(gvRow.FindControl("uxDescriptionTextBox"), TextBox).Text
'db.SaveData(id, description)
End If
End Sub
Private Sub DeleteData(ByVal rowKey as DataKey)
'TODO: Code the DeleteData procedure
'Dim id as Integer = Convert.ToInt32(rowKey("ID"))
'db.DeleteData(id)
End Sub
Private Sub uxAddNewButton_Click(ByVal sender As Object, ByVal e As EventArgs) Handles uxAddNewButton.Click
_gridViewExt.AddNew()
End Sub
GridViewExtender Class
C#
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Data;
public delegate DataTable EmptyDelegate();
public delegate void DataKeyDelegate(DataKey rowKey);
public delegate void GridViewRowDelegate(DataKey rowKey, GridViewRow gvRow);
public class GridViewExtender
{
private GridView _gridView;
private string _identifyingField;
private EmptyDelegate _requeryHandler;
private DataKeyDelegate _deleteHandler;
private GridViewRowDelegate _updateHandler;
//- Constructor -------------------------------------------------------------------------------
public GridViewExtender(GridView gridView, string identifyingField, EmptyDelegate
requeryHandler, DataKeyDelegate deleteHandler, GridViewRowDelegate updateHandler)
{
_gridView = gridView;
_identifyingField = identifyingField;
_requeryHandler = requeryHandler;
_deleteHandler = deleteHandler;
_updateHandler = updateHandler;
_gridView.RowDataBound
+= new GridViewRowEventHandler(_gridView_RowDataBound);
_gridView.RowEditing
+= new GridViewEditEventHandler(_gridView_RowEditing);
_gridView.RowCancelingEdit
+= new GridViewCancelEditEventHandler(_gridView_RowCancelingEdit);
_gridView.RowDeleting
+= new GridViewDeleteEventHandler(_gridView_RowDeleting);
_gridView.RowUpdating
+= new GridViewUpdateEventHandler(_gridView_RowUpdating);
}
//- Public Methods ----------------------------------------------------------------------------
public void AddNew()
{
BindToDataTable(-1, true);
}
//---------------------------------------------------------------------------------------------
public void Requery()
{
this.EditIndex = this.EditIndex;
}
//---------------------------------------------------------------------------------------------
public bool TryGetDataRow(GridViewRow row, DataRow dataRow)
{
bool result = false;
DataRowView drv = row.DataItem as DataRowView;
if (drv != null)
{
dataRow = drv.Row;
result = (dataRow != null);
}
return result;
}
//- Private Methods ---------------------------------------------------------------------------
private void BindToDataTable(int editIndex)
{
BindToDataTable(editIndex, false);
}
//---------------------------------------------------------------------------------------------
private void BindToDataTable(int editIndex, bool addNew)
{
_gridView.EditIndex = editIndex;
if (_requeryHandler != null)
{
DataTable t = _requeryHandler();
if (addNew)
{
foreach (DataColumn col in t.Columns)
col.AllowDBNull = true;
DataRow newRow = t.NewRow();
t.Rows.Add(newRow);
}
_gridView.DataSource = t;
if (addNew)
_gridView.EditIndex = t.Rows.Count - 1;
_gridView.DataBind();
foreach (GridViewRow row in _gridView.Rows)
{
if (row.RowType != DataControlRowType.DataRow)
{
SetVisibility(row, "uxDeleteButton", false);
SetVisibility(row, "uxEditButton", false);
SetVisibility(row, "uxSaveButton", false);
SetVisibility(row, "uxCancelButton", false);
}
else
{
bool editMode = (row.RowIndex == _gridView.EditIndex);
SetVisibility(row, "uxDeleteButton", !editMode);
SetVisibility(row, "uxEditButton", !editMode);
SetVisibility(row, "uxSaveButton", editMode);
SetVisibility(row, "uxCancelButton", editMode);
}
}
}
}
//---------------------------------------------------------------------------------------------
private int EditIndex
{
get { return _gridView.EditIndex; }
set { BindToDataTable(value); }
}
//- Event Handlers ----------------------------------------------------------------------------
private void _gridView_RowDataBound(object sender, GridViewRowEventArgs e)
{
try
{
if (e.Row != null && e.Row.RowType == DataControlRowType.DataRow &&
e.Row.DataItem != null)
{
DataRow dataRow = (e.Row.DataItem as DataRowView).Row;
if (dataRow != null && dataRow[_identifyingField] != null)
{
string identifier = dataRow[_identifyingField].ToString();
WebControl control = e.Row.FindControl("uxDeleteButton") as WebControl;
ImageButton button = null;
if (control != null)
{
button = control as ImageButton;
button.OnClientClick = "confirm('Delete [" + identifier.Replace("'", "\\'")
+ "]?')'";
}
}
}
}
catch (Exception ex)
{
throw ex;
}
}
//---------------------------------------------------------------------------------------------
private void _gridView_RowEditing(object sender, GridViewEditEventArgs e)
{
BindToDataTable(e.NewEditIndex);
}
//---------------------------------------------------------------------------------------------
private void _gridView_RowCancelingEdit(object sender, GridViewCancelEditEventArgs e)
{
BindToDataTable(-1);
}
//---------------------------------------------------------------------------------------------
private void _gridView_RowDeleting(object sender, GridViewDeleteEventArgs e)
{
if (_deleteHandler != null & _requeryHandler != null)
{
try
{
_deleteHandler(_gridView.DataKeys[e.RowIndex]);
BindToDataTable(-1);
}
catch //(Exception ex)
{
e.Cancel = true;
}
}
}
//---------------------------------------------------------------------------------------------
private void _gridView_RowUpdating(object sender, GridViewUpdateEventArgs e)
{
if (_updateHandler != null & _requeryHandler != null)
{
try
{
_updateHandler(_gridView.DataKeys[e.RowIndex], _gridView.Rows[e.RowIndex]);
BindToDataTable(-1);
}
catch
{
e.Cancel = true;
}
}
}
//- Helper Functions --------------------------------------------------------------------------
private static void SetVisibility(GridViewRow row, string controlName, bool visible)
{
WebControl control = row.FindControl(controlName) as WebControl;
if (control != null)
control.Visible = visible;
}
}
Visual Basic
Imports Microsoft.VisualBasic
Imports System.Data
Public Delegate Function EmptyDelegate() As DataTable
Public Delegate Sub DataKeyDelegate(ByVal rowKey As DataKey)
Public Delegate Sub GridViewRowDelegate(ByVal rowKey As DataKey, ByVal gvRow As GridViewRow)
Public Class GridViewExtender
Private WithEvents _gridView As GridView
Private _identifyingField As String
Private _requeryHandler As EmptyDelegate
Private _deleteHandler As DataKeyDelegate
Private _updateHandler As GridViewRowDelegate
'-- Constructor -------------------------------------------------------------------------------
Public Sub New(ByVal gridView As GridView, ByVal identifyingField As String, ByVal _
requeryHandler As EmptyDelegate, ByVal deleteHandler As DataKeyDelegate, ByVal updateHandler As _
GridViewRowDelegate)
_gridView = gridView
_identifyingField = identifyingField
_requeryHandler = requeryHandler
_deleteHandler = deleteHandler
_updateHandler = updateHandler
End Sub
'-- Public Methods ----------------------------------------------------------------------------
Public Sub AddNew()
BindToDataTable(-1, True)
End Sub
'----------------------------------------------------------------------------------------------
''' <summary>
''' Gets or sets the EditIndex of the grid. After setting the EditIndex, requeries the grid.
''' </summary>
''' <value>Specify -1 to have no row in edit mode.</value>
Public Property EditIndex() As Integer
Get
Return _gridView.EditIndex
End Get
Set(ByVal value As Integer)
BindToDataTable(value)
End Set
End Property
'----------------------------------------------------------------------------------------------
Public Sub Requery()
Me.EditIndex = Me.EditIndex
End Sub
'-- Private Methods ---------------------------------------------------------------------------
Private Sub BindToDataTable(ByVal editIndex As Integer, Optional ByVal addNew As Boolean = False)
_gridView.EditIndex = editIndex
If _requeryHandler IsNot Nothing Then
Dim t As DataTable = _requeryHandler()
If addNew Then
For Each col As DataColumn In t.Columns
col.AllowDBNull = True
Next
Dim newRow As DataRow = t.NewRow()
t.Rows.Add(newRow)
End If
_gridView.DataSource = t
If addNew Then
_gridView.EditIndex = t.Rows.Count - 1
End If
_gridView.DataBind()
For Each row As GridViewRow In _gridView.Rows
Dim editMode As Boolean = (row.RowIndex = _gridView.EditIndex)
SetVisibility(row, "uxDeleteButton", Not editMode)
SetVisibility(row, "uxEditButton", Not editMode)
SetVisibility(row, "uxSaveButton", editMode)
SetVisibility(row, "uxCancelButton", editMode)
Next
End If
End Sub
'-- Event Handlers ----------------------------------------------------------------------------
Private Sub _gridView_RowDataBound(ByVal sender As Object, ByVal e As _
GridViewRowEventArgs) Handles _gridView.RowDataBound
Try
If e.Row IsNot Nothing AndAlso e.Row.RowType = DataControlRowType.DataRow AndAlso _
e.Row.DataItem IsNot Nothing Then
Dim dataRow As DataRow = CType(e.Row.DataItem, DataRowView).Row
If dataRow IsNot Nothing Then
'-- Init Delete Button --------------------------------------------------------
If dataRow(_identifyingField) IsNot Nothing Then
Dim identifier As String = dataRow(_identifyingField).ToString()
Dim control As WebControl = _
CType(e.Row.FindControl("uxDeleteButton"), WebControl)
Dim button As ImageButton = Nothing
If control IsNot Nothing Then
button = CType(control, ImageButton)
button.OnClientClick = "confirm('Delete [" & _
identifier.Replace("'", "\'") & "]?');"
End If
End If
End If
End If
Catch ex As Exception
Throw ex
End Try
End Sub
'----------------------------------------------------------------------------------------------
Private Sub _gridView_RowEdit(ByVal sender As Object, ByVal e As GridViewEditEventArgs) _
Handles _gridView.RowEditing
BindToDataTable(e.NewEditIndex)
End Sub
'----------------------------------------------------------------------------------------------
Private Sub _gridView_RowCancellingEdit(ByVal sender As Object, ByVal e As _
GridViewCancelEditEventArgs) Handles _gridView.RowCancelingEdit
BindToDataTable(-1)
End Sub
'----------------------------------------------------------------------------------------------
Private Sub _gridView_RowDeleting(ByVal sender As Object, ByVal e As GridViewDeleteEventArgs) _
Handles _gridView.RowDeleting
If _deleteHandler IsNot Nothing And _requeryHandler IsNot Nothing Then
Try
_deleteHandler(_gridView.DataKeys(e.RowIndex))
BindToDataTable(-1)
Catch ex As Exception
e.Cancel = True
End Try
End If
End Sub
'----------------------------------------------------------------------------------------------
Private Sub _gridView_RowUpdating(ByVal sender As Object, ByVal e As GridViewUpdateEventArgs) _
Handles _gridView.RowUpdating
If _updateHandler IsNot Nothing And _requeryHandler IsNot Nothing Then
Try
_updateHandler(_gridView.DataKeys(e.RowIndex), _gridView.Rows(e.RowIndex))
BindToDataTable(-1)
Catch ex As Exception
e.Cancel = True
End Try
End If
End Sub
'----------------------------------------------------------------------------------------------
Public Function TryGetDataRow(ByVal row As GridViewRow, ByRef dataRow As DataRow) As Boolean
Dim result As Boolean = False
Dim drv As DataRowView = CType(row.DataItem, DataRowView)
If drv IsNot Nothing Then
dataRow = drv.Row
result = (dataRow IsNot Nothing)
End If
Return result
End Function
'-- Helper Functions --------------------------------------------------------------------------
Private Shared Sub SetVisibility(ByVal row As GridViewRow, ByVal controlName As String, ByVal _
visible As Boolean)
Dim control As WebControl = CType(row.FindControl(controlName), WebControl)
If control IsNot Nothing Then
control.Visible = visible
End If
End Sub
End Class