Search code examples
asp.netvb.netaspxgridview

ASP/VB - Gridview - Get row when checkbox is checked


I have created a gridview where one of the columns is a checkbox. I am attempting to use a listener to catch the row that is checked, then send the boolean value of the checkbox back to update the database for whichever datakey that row is carrying.

My ASPX gridview:

 <asp:TableRow ID="trgv2" runat="server" Width="100%">
                <asp:TableCell>
                    <asp:GridView runat="server" ID="gvStuff" DataKeyNames="IDNo" AllowSorting="true" AutoGenerateColumns="false" Width="100%" AllowPaging="true" BackColor="white" CssClass="ASPGrid">
                        <EditRowStyle VerticalAlign="Bottom" BackColor="#dce7f5" />
                        <HeaderStyle BackColor="LightGray" />
                        <SelectedRowStyle BackColor="#ddedf9" />
                        <EmptyDataRowStyle BackColor="#dce7f5" />
                        <PagerSettings Mode="Numeric" />
                        <Columns>
                            <asp:BoundField DataField="IDNo" HeaderText="ID No." SortExpression="IDNo" ItemStyle-Width="18%" HeaderStyle-HorizontalAlign="Left" ItemStyle-HorizontalAlign="Left" />
                            <asp:BoundField DataField="Description" HeaderText="Description" ItemStyle-Width="48%" HeaderStyle-HorizontalAlign="Left" ItemStyle-HorizontalAlign="Left" />
                            <asp:TemplateField HeaderText="Confirmed" ItemStyle-Width="38%" HeaderStyle-HorizontalAlign="Left">
                                <ItemTemplate>
                                    <asp:Checkbox runat="server" DataField="Confirmed" HeaderText="Confirmed" ID="chkConfirmed" OnCheckedChanged="chkConfirmed_CheckedChanged" AutoPostBack="true" />
                                </ItemTemplate>
                            </asp:TemplateField>
                            <asp:TemplateField>
                                <ItemTemplate>
                                    <asp:HiddenField runat="server" ID="hdnchk" Value="<%# Container.DataItem.Active %>" />
                                </ItemTemplate>
                            </asp:TemplateField>
                        </Columns>
                    </asp:GridView>
                </asp:TableCell>
            </asp:TableRow>

I attempted to use a hidden field in order to grab when a column is active, but I'm totally unsure if this method is effective, or if my code is being used correctly.

My VB chkConfirmed_CheckedChanged:

Protected Sub chkConfirmed_CheckedChanged(ByVal sender As Object, ByVal e As EventArgs)
    Dim chkRow As GridViewRow
    For Each row As GridViewRow In gvStuff.Rows
        chkRow  = row.Cells(0).FindControl("hdnchk")
    Next
    UpdateStatus(chkRow)
End Sub

Here, I would find the row that has been "selected" (by being checked), and pass that row into an Update function to update the database. Then reload my grid. But my method doesn't seem to be working at all and I've run into a wall. Is there an easier way to get the "selected" row that has been checked?


Solution

  • Not sure what you mean by "listener".

    We have a plain-Jane check box dropped into that row.

    When you click box that control, we have a event stub, and we have auto-post back.

    Now it is a simple matter to get/grab the current row, and do whatever processing we wish.

    And you do not need a hidden field for the row index.

    And you do not need a hidden field for the row PK id.

    In fact, if you using datakeys then we NEVER have to expose the database PK id's to the client side (and we should not for security reasons).

    But, that is "exaclty" what the data keys feature does for us.

    And in most cases, I would think the user selects, clicks on "many" check boxs, and then a final submit type of button outside at the bottom of the gv to process the selected rows.

    However, let's stick with the check box event, and autopost back = true.

    So, say this gv:

    <h3>Hotels</h3>
    <asp:GridView ID="GridView1" runat="server" Width="40%"
        AutoGenerateColumns="False" DataKeyNames="ID" 
        CssClass="table table-hover table-striped">
        <Columns>
            <asp:BoundField DataField="FirstName" HeaderText="FirstName" />
            <asp:BoundField DataField="LastName" HeaderText="LastName" />
            <asp:BoundField DataField="HotelName" HeaderText="HotelName" />
            <asp:BoundField DataField="City" HeaderText="City" />
            <asp:BoundField DataField="Description" HeaderText="Description" />
            <asp:TemplateField HeaderText="Select" ItemStyle-HorizontalAlign="Center">
                <ItemTemplate>
                    <asp:CheckBox ID="chkSel" runat="server" 
                        AutoPostBack="true"
                        OnCheckedChanged="chkSel_CheckedChanged"
                        />
                </ItemTemplate>
            </asp:TemplateField>
        </Columns>
    </asp:GridView>
    

    Code to load GV:

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
    
        If Not IsPostBack Then
            LoadGrid()
        End If
    
    End Sub
    
    Sub LoadGrid()
    
        Dim cmdSQL As New SqlCommand("SELECT * FROM tblHotelsA ORDER BY HotelName")
        GridView1.DataSource = MyrstP(cmdSQL)
        GridView1.DataBind()
    
    End Sub
    

    And now we see/have this:

    enter image description here

    OK, so now the check box event.

    Protected Sub chkSel_CheckedChanged(sender As Object, e As EventArgs)
    
        Dim ckSel As CheckBox = sender
        Dim gRow As GridViewRow = ckSel.NamingContainer
    
        Dim PK As Integer = GridView1.DataKeys(gRow.RowIndex).Item("ID")
    
        Debug.Print($"Data base PK for row click = {PK}")
        Debug.Print($"Row index clicked = {gRow.RowIndex}")
    
        Debug.Print($"Check box value (checked) = {ckSel.Checked}")
    
        Debug.Print($"Hotel Name = {gRow.Cells(2).Text}")
    
    End Sub
    

    output:

    Data base PK for row click = 1
    Row index clicked = 3
    Check box value (checked) = True
    Hotel Name = Mountain View Hotel
    

    So a VERY nice tip/trick?

    For any button, dropdown, or in this case a check box?

    You can use that namingcontainer approach. That "naming" container works for listview, gridview, repeater's etc.

    You note how we don't (never) required to create some hidden field for the database pk ID. That comes from datakeys, and it not only saves the mess of having to include the ID in the gv markup (we don't), but we also don't' have to try and hide it with a hidden field. Even better it is 100% server side managed automatic for us.

    As I pointed out in most cases, you don't need (or want) a event trigger for that check box, since in most cases you would (I assume) allow the user to check box any number of boxes, and the the above button below the gv would/could then process the rows with the checked rows like this:

    Protected Sub cmdShowSelected_Click(sender As Object, e As EventArgs)
    
        Dim sPKList As String = ""
        For Each gRow As GridViewRow In GridView1.Rows
    
            Dim pkID As Integer = GridView1.DataKeys(gRow.RowIndex).Item("ID")
            Dim chkbox As CheckBox = gRow.FindControl("chkSel")
            If chkbox.Checked Then
                If sPKList <> "" Then sPKList &= ","
    
                sPKList &= pkID
    
            End If
        Next
    
        Label1.Text = $"List of PK id selected = {sPKList}"
    
    End Sub
    

    Hence this result:

    enter image description here

    One more nice FYI?

    Note how I used the bootstrap class to make the gv look nice.

    that was :

    CssClass="table table-hover table-striped"
    

    That will not only lay out the gv nice, have alternating rows without a alternating template (they are terrible), and a nice table hover?

    Nothing else needs be done. Do note if you add "table", then it will automatic expand to full screen width. If you don't want that, then add a width="50%" or whatever to the gv.