.<1> - }
Features
The GridView
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.
Sample Implementation
To use this control, you need to follow the instructions in the Consuming Custom Controls in ASP.NET article.
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 GridView
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.
{copytext|aspx}
<%-- TODO: Change the DataKeysNames property appropriate to your application --%>
<abc:GridView runat="server" ID="uxGridView" 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"
/>
</ItemTemplate>
<EditItemTemplate>
<%-- TODO: Specify the validation group 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"
/>
</EditItemTemplate>
</asp:TemplateField>
</Columns>
</abc:GridView>
<asp:Button runat="server" ID="uxAddNewButton" Text="Add New" />
Code-Behind
Copy the following code into your code-behind file.
C#
protected void Page_Load(object sender, EventArgs e)
{
// TODO: Change the first parameter appropriate to your implementation
uxGridView.Initialize("Description",
new EmptyDelegate(QueryData),
new DataKeyDelegate(DeleteData),
new GridViewRowDelegate(UpdateData));
if (!Page.IsPostBack)
uxGridView.Requery();
}
private DataTable QueryData()
{
return null;
//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)
{
uxGridView.AddNew();
}
Visual Basic
Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Load
' TODO: Change the first parameter appropriate to your implementation
uxGridView.Initialize("Description", _
New EmptyDelegate(AddressOf QueryData), _
New DataKeyDelegate(AddressOf DeleteData), _
New GridViewRowDelegate(AddressOf UpdateData))
If Not Page.IsPostBack Then
uxGridView.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
uxGridView.AddNew()
End Sub
Adjust the Code
Retrieve Data
- Get SP — Write a stored procedure to retrieve the data
- Typed DataSet — In a typed dataset create a data table based on the stored procedure.
- Default Values — Set default values for new rows in the typed DataSet.
- QueryData — Adjust the code for the
QueryData
method to retrieve the appropriate data and return the typed DataTable. - DataKeyNames — In the ASPX code, change the
DataKeyNames
property of the GridView. - Columns — Add columns to the GridView to display/edit fields.
- IdentifyingField — On the
uxGridView.Initialize()
method call, adjust the first parameter. - Test Display — Test that the grid displays rows correctly.
Save Data
- Save SP — Write a stored procedure that saves the data.
- UpdateData — Adjust the code for the
UpdateData
method to save changes to a row. - Test UpdateData — Test the saving of a row.
- Test AddNew — Test the adding of a new row.
Delete Data
- Delete SP — Write a stored procedure to delete a row.
- DeleteData — Adjust the code for the
DeleteData
method to delete a row. - Test DeleteData — Test the deleting of a row.
Source Code
C#
{copytext|SourceCs}
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);
namespace JasinskiSoftware
{
public class GridView : System.Web.UI.WebControls.GridView
{
private string _identifyingField;
private EmptyDelegate _requeryHandler;
private DataKeyDelegate _deleteHandler;
private GridViewRowDelegate _updateHandler;
private HiddenField _rowCountField;
//- Constructor -------------------------------------------------------------------------------
public GridView()
{
this.AutoGenerateColumns = false;
this.CellPadding = 3;
this.CellSpacing = 0;
}
public void Initialize(string identifyingField, EmptyDelegate requeryHandler,
DataKeyDelegate deleteHandler, GridViewRowDelegate updateHandler)
{
Initialize(identifyingField, requeryHandler, deleteHandler, updateHandler, null);
}
public void Initialize(string identifyingField, EmptyDelegate requeryHandler,
DataKeyDelegate deleteHandler, GridViewRowDelegate updateHandler, HiddenField
rowCountField)
{
_identifyingField = identifyingField;
_requeryHandler = requeryHandler;
_deleteHandler = deleteHandler;
_updateHandler = updateHandler;
_rowCountField = rowCountField;
base.RowDataBound
+= new GridViewRowEventHandler(_gridView_RowDataBound);
base.RowEditing
+= new GridViewEditEventHandler(_gridView_RowEditing);
base.RowCancelingEdit
+= new GridViewCancelEditEventHandler(_gridView_RowCancelingEdit);
base.RowDeleting
+= new GridViewDeleteEventHandler(_gridView_RowDeleting);
base.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)
{
this.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);
}
this.DataSource = t;
if (addNew)
this.EditIndex = t.Rows.Count - 1;
this.DataBind();
}
}
//---------------------------------------------------------------------------------------------
private int EditIndex
{
get { return this.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();
ImageButton button = e.Row.FindControl("uxDeleteButton") as ImageButton;
if (button != null)
{
string s = "'Delete [";
s += identifier.Replace("'", "\'");
s += "]?'";
s = "javascript:if (confirm(" + s + ")==false){event.returnValue=false;";
s += "return false;}else{return true;};";
button.Attributes.Add ("onclick", s);
}
}
}
}
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(base.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(base.DataKeys[e.RowIndex], base.Rows[e.RowIndex]);
BindToDataTable(-1);
}
catch
{
e.Cancel = true;
}
}
}
}
}
Visual Basic
{copytext|SourceVb}
Imports System
Imports System.Data
Imports System.Configuration
Imports System.Web
Imports System.Web.Security
Imports System.Web.UI
Imports System.Web.UI.WebControls
Imports System.Web.UI.WebControls.WebParts
Imports System.Web.UI.HtmlControls
Imports System.Diagnostics
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)
Namespace AcmeBroomCompany
Public Class GridView
Inherits System.Web.UI.WebControls.GridView
Private _identifyingField As String
Private _requeryHandler As EmptyDelegate
Private _deleteHandler As DataKeyDelegate
Private _updateHandler As GridViewRowDelegate
Private _rowCountField As HiddenField
'- Constructor and Initializer -----------------------------------------------------------
Public Sub New()
' set default settings
Me.AutoGenerateColumns = False
Me.CellPadding = 3
Me.CellSpacing = 0
End Sub
Public Sub Initialize(ByVal identifyingField As String, ByVal requeryHandler As _
EmptyDelegate, ByVal deleteHandler As DataKeyDelegate, ByVal updateHandler As _
GridViewRowDelegate, Optional ByVal rowCountField As HiddenField = Nothing)
_identifyingField = identifyingField
_requeryHandler = requeryHandler
_deleteHandler = deleteHandler
_updateHandler = updateHandler
_rowCountField = rowCountField
AddHandler MyBase.RowDataBound, AddressOf _gridView_RowDataBound
AddHandler MyBase.RowEditing, AddressOf _gridView_RowEditing
AddHandler MyBase.RowCancelingEdit, AddressOf _gridView_RowCancelingEdit
AddHandler MyBase.RowDeleting, AddressOf _gridView_RowDeleting
AddHandler MyBase.RowUpdating, AddressOf _gridView_RowUpdating
End Sub
'- Public Methods ----------------------------------------------------------------------------
Public Sub AddNew()
If Me.Controls.Count <= 0 Or _rowCountField Is Nothing Then
BindToDataTable(-1, True)
Else
Dim table As Table = CType(Me.Controls(0), Table)
Dim rowIndex As Integer = table.Rows.Count
RowCount += 1
' subtract one for the header
While table.Rows.Count - 1 <= RowCount
Dim newGvRow As GridViewRow = Me.CreateRow(rowIndex, rowIndex, _
DataControlRowType.DataRow, DataControlRowState.Insert)
Dim fields As DataControlField() = New DataControlField(Me.Columns.Count - 1) {}
MyBase.Columns.CopyTo(fields, 0)
MyBase.InitializeRow(newGvRow, fields)
table.Controls.AddAt(rowIndex, newGvRow)
End While
End If
End Sub
Public Sub Requery()
Me.EditIndex = Me.EditIndex
End Sub
'- Private Methods ---------------------------------------------------------------------------
Private Sub BindToDataTable(ByVal editIndex As Integer)
BindToDataTable(editIndex, False)
End Sub
Private Sub BindToDataTable(ByVal editIndex As Integer, ByVal addNew As Boolean)
Try
MyBase.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
MyBase.DataSource = t
If addNew Then
MyBase.EditIndex = t.Rows.Count - 1
End If
MyBase.DataBind()
End If
Catch ex As Exception
Throw ex
End Try
End Sub
Private Property EditIndex() As Integer
Get
Return MyBase.EditIndex
End Get
Set(ByVal value As Integer)
BindToDataTable(value)
End Set
End Property
Private Property RowCount() As Integer
Get
Dim result As Integer
If _rowCountField Is Nothing OrElse Not Integer.TryParse(_rowCountField.Value, _
result) Then
result = -1
End If
Return result
End Get
Set(ByVal value As Integer)
_rowCountField.Value = value.ToString()
End Set
End Property
'- Event Handlers ----------------------------------------------------------------------------
Private Sub _gridView_RowDataBound(ByVal sender As Object, ByVal e As GridViewRowEventArgs)
Try
If e.Row IsNot Nothing AndAlso e.Row.RowType = DataControlRowType.DataRow AndAlso _
e.Row.DataItem IsNot Nothing Then
Dim dataRow As DataRow = TryCast(e.Row.DataItem, DataRowView).Row
If dataRow IsNot Nothing AndAlso dataRow(_identifyingField) IsNot Nothing Then
Dim identifier As String = dataRow(_identifyingField).ToString()
Dim button As ImageButton = TryCast(e.Row.FindControl("uxDeleteButton"), _
ImageButton )
If button IsNot Nothing Then
Dim s As String = "'Delete ["
s &= identifier.Replace("'", "\'")
s &= "]?'"
s = "javascript:if (confirm(" & s & ")==false){event.returnValue=false;"
s &= "return false;}else{return true;};"
button.Attributes.Add("onclick", s)
End If
End If
End If
Catch ex As Exception
Throw ex
End Try
End Sub
Private Sub _gridView_RowEditing(ByVal sender As Object, ByVal e As GridViewEditEventArgs)
BindToDataTable(e.NewEditIndex)
End Sub
Private Sub _gridView_RowCancelingEdit(ByVal sender As Object, ByVal e As _
GridViewCancelEditEventArgs)
BindToDataTable(-1)
End Sub
Private Sub _gridView_RowDeleting(ByVal sender As Object, ByVal e As _
GridViewDeleteEventArgs)
If _deleteHandler IsNot Nothing And _requeryHandler IsNot Nothing Then
Try
_deleteHandler(MyBase.DataKeys(e.RowIndex))
BindToDataTable(-1)
Catch
'(Exception ex)
e.Cancel = True
End Try
End If
End Sub
' This event handler should fire when the user click a row button with the "Update" command
Private Sub _gridView_RowUpdating(ByVal sender As Object, ByVal e As GridViewUpdateEventArgs)
If _updateHandler IsNot Nothing And _requeryHandler IsNot Nothing Then
Try
_updateHandler(MyBase.DataKeys(e.RowIndex), MyBase.Rows(e.RowIndex))
BindToDataTable(-1)
Catch ex As Exception
Debug.Print(ex.Message)
e.Cancel = True
End Try
End If
End Sub
End Class
End Namespace