Row Clickable GridView

June 2, 2008 05:25 by wjchristenson2

In this post, I am going to show how we can make a GridView row clickable.  What I mean by this is when the user clicks on a row, it will fire a postback to the server that the programmer can handle.

There are endless uses for this functionality.  You may want to toggle a row into edit mode or display/bind another GridView on your page when a user clicks on a row.  I actually use this feature a lot.  In my opinion it is easier on the user if they can simply click on a row to perform a desired action.

  

RowClickGridView Class/Control:

In order to make rows clickable, we are going to create a custom GridView control.  We are going to inherit from System.Web.UI.WebControls.GridView because we want all the functionality of the basic GridView plus our own enhancements.  We will name the control "RowClickGridView".

'key that is used for our RowClicked event handler
Private Shared ReadOnly RowClickedEventKey As Object = New Object()

<DefaultValue(False), Description("Indicates whether or not rows are clickable.")> _
      Public Property RowClick_Enabled() As Boolean
    Get
        If Not IsNothing(ViewState("RowClick_Enabled")) Then
            Return DirectCast(ViewState("RowClick_Enabled"), Boolean)
        Else
            Return False
        End If
    End Get
    Set(ByVal value As Boolean)
        ViewState("RowClick_Enabled") = value
    End Set
End Property

<DefaultValue(""), Description("Specifies the ToolTip for clickable rows."), Category("Appearance")> _
      Public Property RowClick_ToolTip() As String
    Get
        If Not IsNothing(ViewState("RowClick_ToolTip")) Then
            Return ViewState("RowClick_ToolTip").ToString()
        Else
            Return String.Empty
        End If
    End Get
    Set(ByVal value As String)
        ViewState("RowClick_ToolTip") = value
    End Set
End Property

Here we create 2 properties and 1 class variable.  The RowClickedEventKey in line 2 is later used for our event handling.  We have 2 properties.  I want the RowClicked functionality to not trigger postbacks unless I enable it.  I would also like to be able to set ToolTips on the row if it is clickable.  We persist the properties via the ViewState so that if the default values get changed across postbacks programmatically, our control will remember them.

Protected Overrides Sub PrepareControlHierarchy()
    MyBase.PrepareControlHierarchy()

    'wire RowClick event & RowClick tooltip for rows if RowClicked is enabled
    If Me.RowClick_Enabled Then
        Dim argsData As String = String.Empty
        For Each row As GridViewRow In Me.Rows
            'if row is a data row & it's not the edit row
            If row.RowType = DataControlRowType.DataRow And Me.EditIndex <> row.RowIndex Then
                'create argument - pass the row index
                argsData = "rc" & row.RowIndex.ToString()

                'wire javascript to the row for the RowClicked event
                row.Attributes.Add("onClick", Me.Page.ClientScript.GetPostBackEventReference(Me, argsData))

                'if the RowClick ToolTip is supplied
                If Not String.IsNullOrEmpty(Me.RowClick_ToolTip) Then
                    'apply tooltip to row
                    row.ToolTip = Me.RowClick_ToolTip
                End If
            End If
        Next
    End If
End Sub

The PrepareControlHierarchy() method is new in .NET 2.0.  What this method does is basically establishes the control hierarchy.  So before we tap into the GridView's control hierarchy, we call the MyBase.PrepareControlHierarchy().  We only want to make rows clickable if we've enabled it, so we check that irst on line 5.  After the hierarchy is ready, we loop through the rows of the GridView and acquire the rows we wish to make clickable (line 9).  Once we have a row we wish to make clickable, we form the argument data and wire the row to fire a postback when clicked.  We also add our row click tooltip if supplied.

Protected Overrides Sub RaisePostBackEvent(ByVal eventArgument As String)
    'if a row clicked event
    If eventArgument.StartsWith("rc") Then
        'get the index of the row that raised the event
        Dim index As Integer = Int32.Parse(eventArgument.Substring(2))

        'create our instance of GridViewRowClickedEventArgs passing the GridViewRow clicked
        Dim args As GridViewRowClickedEventArgs = New GridViewRowClickedEventArgs(Me.Rows(index))

        'raise the RowClicked event
        OnRowClicked(args)
    Else
        'raise any other event (not row clicked)
        MyBase.RaisePostBackEvent(eventArgument)
    End If
End Sub

In order to raise our custom event if the row clicked, we need to override the GridView's RaisePostBackEvent method.  This method raises the GridView's events when it posts back to the server.  We check to see if the row clicked event was the trigger in line 3.  We then acquire the row index that fired the event by stripping it out of the eventArgument string in line 5.  We want to be able to tap into the entire row when the event is fired later, so we are going to create a custom event argument class (posted below).  We instantiate the GridViewRowClickedEventArgs class by passing in the GridViewRow. and then call our OnRowClicked() method to raise the event.

Protected Overridable Sub OnRowClicked(ByVal e As GridViewRowClickedEventArgs)
    'raise the RowClicked event
    RaiseEvent RowClicked(Me, e)
End Sub

Here is the OnRowClicked() helper method mentioned above.  We simply raised the RowClicked event.

'setup our EventHandler for RowClicked
Public Custom Event RowClicked As EventHandler(Of GridViewRowClickedEventArgs)
    AddHandler(ByVal value As EventHandler(Of GridViewRowClickedEventArgs))
        Events.AddHandler(RowClickedEventKey, value)
    End AddHandler

    RemoveHandler(ByVal value As EventHandler(Of GridViewRowClickedEventArgs))
        Events.RemoveHandler(RowClickedEventKey, value)
    End RemoveHandler

    RaiseEvent(ByVal sender As Object, ByVal e As GridViewRowClickedEventArgs)
        Dim ev As EventHandler(Of GridViewRowClickedEventArgs) = TryCast(Events(RowClickedEventKey), EventHandler(Of GridViewRowClickedEventArgs))
        If Not IsNothing(ev) Then
            ev(sender, e)
        End If
    End RaiseEvent
End Event

This is the EventHandler for our RowClicked event.  You can see the add, remove, and raise event implementations above.  The important thing to note here is the use of our custom event argument class (GridViewRowClickedEventArgs).

  

GridViewRowClickedEventArgs Class:

In our RowClickGridView control, you noticed we used a custom event argument class for our event handler.  Here is the code:

'our custom event argument class for the RowClicked event
Public Class GridViewRowClickedEventArgs
    Inherits EventArgs

    Private _row As GridViewRow

    Public ReadOnly Property Row() As GridViewRow
        Get
            Return _row
        End Get
    End Property

    Public Sub New(ByVal row As GridViewRow)
        _row = row
    End Sub
End Class

You notice that we inherit from EventArgs and add a property to tap into the GridViewRow that was clicked.  The class requires the row clicked in its constructor.

 

RowClickGridView In Action:

Now that we have our control developed, we can use it.  We first add it to our aspx page and setup our 2 properties:

<p>Row Index Clicked: <asp:Label ID="Label1" runat="server" /></p>
<cc1:RowClickGridView ID="RowClickGridView1" runat="server" 
    AutoGenerateColumns="False" DataKeyNames="CategoryID" 
    DataSourceID="SqlDataSource1" RowClick_Enabled="true" RowClick_ToolTip="Row Click ToolTip">
    <Columns>
        <asp:BoundField DataField="CategoryID" HeaderText="CategoryID" 
            InsertVisible="False" ReadOnly="True" SortExpression="CategoryID" />
        <asp:BoundField DataField="CategoryName" HeaderText="CategoryName" 
            SortExpression="CategoryName" />
        <asp:BoundField DataField="Description" HeaderText="Description" 
            SortExpression="Description" />
    </Columns>
</cc1:RowClickGridView>

Notice we enable row clicking and also set the tooltip we want on clickable rows.   To see what index we clicked, we want to capture the event and set a label control in the code behind.

Protected Sub RowClickGridView1_RowClicked(ByVal sender As Object, ByVal e As GridViewRowClickedEventArgs) Handles RowClickGridView1.RowClicked
    Me.Label1.Text = e.Row.RowIndex.ToString()
End Sub

And that's it!  We've created a custom GridView control that has row click functionality.  I've attached the code for your pleasure.  Enjoy!

Examples_Soln.zip (102.13 kb)

Bookmark and Share