Download Code and Demo Solution - 184.4 KB
Introduction
The ASP.NET GridView
is an excellent control and is widely used, but still lacks some features. This article demonstrates extending the GridView
to add cell click event handling by inheriting from the base GridView
class, overriding and changing some of the properties and behaviour.
Background
After doing some research, there seems to be not a lot of resources with regards to cell click event handling in the ASP.NET GridView
. I have found one or two articles where you have to add some JavaScript functions to the RowDataBound()
event of the GridView
. I wanted an out-of-the-box gridview with this functionality. Finally, I came across a blog post by Jonni Teemu Keiski called Developing a row-clickable GridView, and started from there by applying the same principle to the cells of the GridView
.
Using the code
Adding a designer property: Enable cell-click
Since we opt to have a generic control, we add a property that the programmer can set to enable postback events when a cell is clicked.
<DefaultValue(False)> _
Public Property EnableCellClick() As Boolean
Get
Dim ret As Boolean = False
Dim obj As Object = ViewState("EnableCellClick")
If obj IsNot Nothing Then
ret = CBool(obj)
End If
Return ret
End Get
Set(ByVal value As Boolean)
ViewState("EnableCellClick") = value
End Set
End Property
Adding a class for the arguments of the cell-click event
In order to return the properties of the cell that was clicked, we create a new custom event argument that inherits the base event argument class. We will return the custom event argument in the custom event handler CellClicked()
that we'll create in the next section.
Public Class GridViewCellClickedEventArgs _
Inherits EventArgs
Private mobjCell As TableCell
Private mobjRow As GridViewRow
Private mintColumnIndex As Integer
Public Sub New(ByVal Cell As TableCell, _
ByVal row As GridViewRow, _
ByVal ColumnIndex As Integer)
mobjCell = Cell
mobjRow = row
mintColumnIndex = ColumnIndex
End Sub
Public ReadOnly Property Cell() As TableCell
Get
Return mobjCell
End Get
End Property
Public ReadOnly Property Row() As GridViewRow
Get
Return mobjRow
End Get
End Property
Public ReadOnly Property ColumnIndex() As Integer
Get
Return mintColumnIndex
End Get
End Property
End Class
Creating an event for the cell click
In the next section, we will add a custom event which will return our custom event argument created previously for the programmer to use:
Protected Sub XGridView1_CellClicked(ByVal sender As Object, _
ByVal e As CustomControls.GridViewCellClickedEventArgs) _
Handles XGridView1.CellClicked
Response.Write("Contents of cell clicked: " & e.Cell.Text)
Response.Write("Zero based column index of clicked cell: " & e.ColumnIndex)
End Sub
Adding the custom event
The custom event contains AddHandler
, a RemoveHandler
which simply tells the call to attach or remove the given event handler from the cell's click event.
Lastly, we'll use a RaiseEvent
implementation to raise the event as in the previous section (e.g., XGridView1_CellClicked()
).
Public Custom Event CellClicked As EventHandler(Of GridViewCellClickedEventArgs)
AddHandler(ByVal value As EventHandler(Of GridViewCellClickedEventArgs))
Events.AddHandler(CellClickedEventKey, value)
End AddHandler
RemoveHandler(ByVal value As EventHandler(Of GridViewCellClickedEventArgs))
Events.RemoveHandler(CellClickedEventKey, value)
End RemoveHandler
RaiseEvent(ByVal sender As Object, ByVal e As GridViewCellClickedEventArgs)
Dim ev As EventHandler(Of GridViewCellClickedEventArgs) = _
TryCast(Events(CellClickedEventKey), _
EventHandler(Of GridViewCellClickedEventArgs))
If ev IsNot Nothing Then
ev(sender, e)
End If
End RaiseEvent
End Event
Protected Overridable Sub OnCellClicked(ByVal e As GridViewCellClickedEventArgs)
RaiseEvent CellClicked(Me, e)
End Sub
Adding the attributes of the base control (GridView) to the child controls (TableCell)
The next step is to apply the click event and event arguments to the child control which is the TableCell
of the GridView
. This is done by overriding the PrepareControlHierarchy()
method of the base class.
For i As Integer = 0 To Rows.Count - 1
For j As Integer = 0 To Rows(i).Cells.Count - 1
Dim argsData As String = "cc" & ";" & Rows(i).RowIndex.ToString & _
";" & j.ToString
Me.Rows(i).Cells(j).Attributes.Add("onclick", _
Page.ClientScript.GetPostBackEventReference(Me, argsData))
Next
Next
Handling the postback
Finally, we override the RaisePostBackEvent()
event. In this method, the GridView
's events are raised when a postback happens on the server. We will override the method to determine from the EventArgument
whether the event was caused by clicking a cell. From here, we use the event data to create a new instance of GridViewCellClickedEventArgs
and pass it to the OnCellClicked()
method.
Protected Overrides Sub RaisePostBackEvent(ByVal eventArgument As String)
If eventArgument.StartsWith("cc") Then
Dim lcolIndices() As String = eventArgument.Split(";")
Dim lintRowIndex As Integer = lcolIndices(1).ToString()
Dim lintColumnIndex As Integer = lcolIndices(2).ToString()
Dim args As New GridViewCellClickedEventArgs(Me.Rows(lintRowIndex). _
Cells(lintColumnIndex), Me.Rows(lintRowIndex), lintColumnIndex)
OnCellClicked(args)
Else
MyBase.RaisePostBackEvent(eventArgument)
End If
End Sub
Adding the control to a webpage
<%@ Register Assembly="XGridView"
Namespace="CustomControls" TagPrefix="cc1" %>
<cc1:XGridView ID='XGridView' runat="server" EnableCellClick="True"
DataSourceID="XmlDataSource1" >
</cc1:XGridView>
Note that we have enabled the cell click in the markup, but it can also be set in the property designer in the IDE.
Adding some code to the CellClicked() event
Protected Sub XGridView_CellClicked(ByVal sender As Object, _
ByVal e As CustomControls.GridViewCellClickedEventArgs) _
Handles XGridView.CellClicked
lblResult.Text = "Index of the cell clicked was: " & e.ColumnIndex.ToString
lblResult0.Text = "Value of cell clicked: " & e.Cell.Text.ToString
lblResult1.Text = "Index of the row clicked was: " & e.Row.RowIndex
End Sub