Search code examples
c#asp.netgridviewfindcontrol

I can't seem to find the checkbox I put in a gridview for selection of rows


I am working with a gridview which I want to select a row and then put the row in a datatable to bind with a repeater control. I am having trouble finding the selected rows using the checkbox control that I had put in the gridview. I have searched the internet and have found some information on finding controls recursively. I can find a checkbox control however the results are always a "false" checkedbox. My question, Do I need to do something when the checkbox is checked in order for the gridview to know that there was a change? The checkbox is not bound to any data in my datatable is is only used for selection purposes.

 <asp:GridView ID="GridView1" runat="server" HeaderStyle-BackColor="#191970" HeaderStyle-ForeColor="White" ShowFooter="false" RowStyle-Wrap="false"
            AlternatingRowStyle-BackColor="#80993c" AlternatingRowStyle-ForeColor="White" AutoGenerateColumns="false" GridLines="None" 
            EnableViewState="false" AllowSorting="true" ShowHeaderWhenEmpty="true" EmptyDataText="No Notaries found with the specified criteria." CssClass="GridView1" OnSorting="GridView1_Sorting1">
            <Columns>
                <asp:TemplateField>
                    <ItemTemplate>
                        <asp:CheckBox ID="notaryselect" runat="server" />
                    </ItemTemplate>
                </asp:TemplateField>
                <asp:BoundField DataField="firstname" HeaderText="First Name" SortExpression="FirstName" />
                <asp:BoundField DataField="lastname" HeaderText="Last Name" SortExpression="LastName" />
                <asp:BoundField DataField="suffix" HeaderText="Suffix" />
                <asp:BoundField DataField="city" HeaderText="City" SortExpression="City" />
                <asp:BoundField DataField="state" HeaderText="State" SortExpression="State" />
                <asp:BoundField DataField="zipcode" HeaderText="Zip Code" SortExpression="Zipcode" />
                <asp:TemplateField>
                    <HeaderTemplate>Cell Phone</HeaderTemplate>
                    <ItemTemplate>
                        <asp:HyperLink ID="hyperCellPhone" runat="server" ForeColor="Gold"
                            NavigateUrl='<%# Eval("cellphone", "tel:{0}") %>'
                            Text='<%# Eval("cellphone") %>'></asp:HyperLink>
                    </ItemTemplate>
                </asp:TemplateField>
                <asp:TemplateField>
                    <HeaderTemplate>Email</HeaderTemplate>
                    <ItemTemplate>
                        <asp:HyperLink ID="hyperEmail" runat="server"
                            NavigateUrl='<%# Eval("email", "mailto:{0}") %>'
                            Text='<%# Eval("email") %>'></asp:HyperLink>
                    </ItemTemplate>
                </asp:TemplateField>
                <asp:BoundField DataField="county" HeaderText="County" SortExpression="County" />
                <asp:BoundField DataField="lat" HeaderText="Latitude" />
                <asp:BoundField DataField="long" HeaderText="Longitude" />
            </Columns>
            <FooterStyle BackColor="#507CD1" Font-Bold="True" ForeColor="White" Width="50%" />
        </asp:GridView>

Control check = FindControlRecursive(GridView1.Rows[i], "notaryselect"); 

The above line is some code just to find the checkbox. I was experimenting and found that a checkbox is returned but no matter what they all come back false which is leading me to think that since they are set to unchecked or false at the start I need to do something but I am just not sure. Everything I find on the internet shows it should work. Let me know what your thoughts are.

Here is the code for the recursive function.

 public static Control FindControlRecursive(Control Root, string Id)
{
  if (Root.ID == Id)
    return Root;
  foreach (Control c in Root.Controls)
  {
    Control fc = FindControlRecursive(c, Id);
    if (fc != null)
      return fc;
  }
  return null;
}

I found that code on this site from a similar question and wanted to see if that worked.


Solution

  • You don't need any recursive function.

    So, say this gv with a check box:

    (it can be set to a value in the table, or not - does not matter).

    So, this gv:

                runat="server" CssClass="table" AutoGenerateColumns="false"
                width="42%" DataKeyNames="ID"  >
                <Columns>
                    <asp:BoundField DataField="FirstName" HeaderText="FirstName"  />
                    <asp:BoundField DataField="LastName" HeaderText="LastName"    />
                    <asp:BoundField DataField="HotelName" HeaderText="Hotel Name"    />
                    <asp:BoundField DataField="Description" HeaderText="Description" ItemStyle-Width="270" />
                    <asp:TemplateField>
                        <ItemTemplate>
                            <asp:CheckBox ID="chkActive" runat="server"
                                Checked='<%# Eval("Active") %>' />
                        </ItemTemplate>
                    </asp:TemplateField>
                    <asp:TemplateField HeaderText="View">
                        <ItemTemplate>
                            <asp:Button ID="cmdView" runat="server" Text="view" 
                                CssClass="btn" OnClick="cmdView_Click" />
                        </ItemTemplate>
                    </asp:TemplateField>
                </Columns>
            </asp:GridView>
    

    Code to load is this:

        protected void Page_Load(object sender, EventArgs e)
        {
            if (!IsPostBack)
                LoadData();
        }
    
        void LoadData()
        {
            string strSQL = "SELECT * FROM tblHotelsA ORDER BY HotelName";
            DataTable rstData = MyRst(strSQL);
            GridView1.DataSource = rstData;
            GridView1.DataBind();
        }
    
        public DataTable MyRst(string strSQL)
        {
            DataTable rstData = new DataTable();
            using (SqlConnection conn = new SqlConnection(Properties.Settings.Default.TEST4))
            {
                using (SqlCommand cmdSQL = new SqlCommand(strSQL, conn))
                {
                    cmdSQL.Connection.Open();
                    rstData.Load(cmdSQL.ExecuteReader());
                }
            }
            return rstData;
        }
    

    And we now see/get this:

    enter image description here

    Ok, so for the click/view button, we have this code:

        protected void cmdView_Click(object sender, EventArgs e)
        {
            Button btnView = (Button)sender;
            GridViewRow gRow = (GridViewRow)btnView.NamingContainer;
    
            Debug.Print("Row index click = " + gRow.RowIndex);
            int PK = (int)GridView1.DataKeys[gRow.RowIndex]["ID"];
            Debug.Print("Database PK id = " + PK);
    
            CheckBox ckActive = (CheckBox)gRow.FindControl("chkActive");
    
            if (ckActive.Checked)
                Debug.Print("check box is true");
            else
                Debug.Print("Check box is false");
    
        }
    

    output:

    Row index click = 2
    Database PK id = 7
    Check box is false
    

    So, above is a row click sample.

    But, for all rows, then this:

            foreach (GridViewRow gRow in GridView1.Rows)
            {
                CheckBox ckBox = (CheckBox)gRow.FindControl("chkActive");
                Debug.Print($"Row index = {gRow.RowIndex} Checkbox value = {ckBox.Checked.ToString()}");
            }
    

    output:

    Row index = 0 Checkbox value = True
    Row index = 1 Checkbox value = False
    Row index = 2 Checkbox value = False
    Row index = 3 Checkbox value = True
    Row index = 4 Checkbox value = False
    Row index = 5 Checkbox value = True
    Row index = 6 Checkbox value = True
    Row index = 7 Checkbox value = True
    

    And of course, above could also display the database PK value, and quite nice is such values don't have to be exposed client side in the GV.

    eg:

      int PKID = (int)GridView1.DataKeys[gRow.RowIndex]["ID];