Gridview TextBox value getting null (blank) after button click

Gani_tpt 2,106 Reputation points
2024-05-16T16:11:44.3566667+00:00

i am selecting some checkboxes and trying to enter some feedback value in the corresponding cell of textboxes.

But, I am unable to get Gridview textbox value in all paging when i click save button.

Getting blank value always.

below is my code

<asp:GridView ID="gvCustomer" runat="server" AutoGenerateColumns="false"
                        AllowPaging="true" OnPageIndexChanging="OnPaging" PageSize="10">
                        <Columns>
                            <asp:TemplateField>
                                <HeaderTemplate>
                                    <asp:CheckBox ID="chkAll" runat="server" onclick="SelectAll(this);" />
                                </HeaderTemplate>
                                <ItemTemplate>
                                    <asp:CheckBox ID="ChkBox1" runat="server" onclick="SelectOne(this)" />
                                </ItemTemplate>
                            </asp:TemplateField>
                            <asp:BoundField DataField="CustomerID" HeaderText="Customer Id" />
                            <asp:BoundField DataField="City" HeaderText="City" />
			    <asp:TemplateField>
                                            <HeaderTemplate>
                                                <label></label>
                                            </HeaderTemplate>
                                            <ItemTemplate>
                                                <asp:TextBox ID="txtCustFeedback" runat="server" Text='<%# Eval("CustFeedback")%>'></asp:TextBox>
                                            </ItemTemplate>
                           </asp:TemplateField>
                        </Columns>
                    </asp:GridView>
<asp:Button ID="btnSave" runat="server" Text="Save" OnClick="btnSave_Click />

 protected void btnSave_Click(object sender, EventArgs e)
 {
                    foreach (GridViewRow gvrow in gvCustomer.Rows)
                    {
                        if (gvrow.RowType == DataControlRowType.DataRow)
                        {
                            var checkbox = gvrow.FindControl("ChkBox1") as CheckBox;
                            if (checkbox.Checked)
                            {
                                  TextBox txtCustFeedback = gvrow.FindControl("txtCustFeedback") as TextBox; // For feedback.
                            }
                         }
                      }
 }       

what is the problem and how to get textbox values in all paging

ASP.NET
ASP.NET
A set of technologies in the .NET Framework for building web applications and XML web services.
3,383 questions
C#
C#
An object-oriented and type-safe programming language that has its roots in the C family of languages and includes support for component-oriented programming.
10,521 questions
{count} votes

Accepted answer
  1. Albert Kallal 5,221 Reputation points
    2024-05-19T08:29:10.4633333+00:00

    I'm going to suggest you simply persist the data table.

    The advantages are many with this approach.

    First up, when you are finally done, you can save all changes with one update command.

    And, you can cancel (not save) the changes if you wish.

    It not clear if you check all is to check all rows (in every page), or check all rows in the current page of data. I'll assume you want all rows.

    One bit of information is how many rows in total do you have?

    So, in my case we have some hotels, and your check box, and some text

    So, our markup:

               <asp:GridView ID="GVHotels" runat="server" class="table" 
                   AutoGenerateColumns="false" DataKeyNames="ID"
                   CssClass="table table-hover borderhide"
                   width="40%"
                   AllowPaging="True" 
                   OnPageIndexChanging="GVHotels_PageIndexChanging"
                   >
                   <Columns>
                       <asp:BoundField DataField="ID" HeaderText="ID" />
                       <asp:BoundField DataField="HotelName" HeaderText="Hotel" />
    
                       <asp:TemplateField HeaderText="Feedback">
                           <ItemTemplate>
                               <asp:TextBox ID="txtCustFeedback" runat="server"
                                   Text='<%# Eval("CustFeedback")%>'
                                   style="width:100%" >                               
                               </asp:TextBox>
                           </ItemTemplate>
                       </asp:TemplateField>
    
                       <asp:TemplateField ItemStyle-HorizontalAlign="Center">
                           <HeaderTemplate >
                               <div style="text-align:center">
                               Check All <br />
                               <asp:CheckBox ID="chkAll" runat="server"
                                   OnCheckedChanged="chkAll_CheckedChanged"
                                   AutoPostBack="true" />
                               </div>
                           </HeaderTemplate>
                           <ItemTemplate>
                               <asp:CheckBox ID="ChkBox1" runat="server"
                                   Checked='<%# Eval("Checked") %>' />
                           </ItemTemplate>
                       </asp:TemplateField>
                   </Columns>
    
                    <PagerStyle CssClass="GridPager" VerticalAlign="Bottom" BorderWidth="2" />
    
               </asp:GridView>
    
               <br />
    
                <asp:Button ID="cmdSave" runat="server" Text="Save Edits" 
                    CssClass="btn" OnClick="cmdSave_Click" />
    
                <asp:Button ID="cmdCancel" runat="server" Text="Cancel"
                    CssClass="btn" 
                    style="margin-left:20px"
                    OnClick="cmdCancel_Click"                
                    />
    
    

    And now our code to load the GridView:

    Note close how we pull the data into a data table, and then persist that table into session.

    (this is why I asked how many rows). For say up to 200 rows or so, then this works without delay. If you have 1000's of rows, then we will require a different approach.

            DataTable rstData = new DataTable();
            protected void Page_Load(object sender, EventArgs e)
            {
                if (!IsPostBack)
                {
                    LoadGrid();
                    Session["rstData"] = rstData;
                }
                else
                    rstData = Session["rstData"] as DataTable;
            }
    
            void LoadGrid()
            {
                using (SqlConnection conn = new SqlConnection(Properties.Settings.Default.TEST4))
                {
                    string strSQL = "SELECT * FROM tblHotels ORDER BY HotelName";
                    using (SqlCommand cmdSQL = new SqlCommand(strSQL, conn))
                    {
                        conn.Open();
                        rstData.Load(cmdSQL.ExecuteReader());
                        GVHotels.DataSource = rstData;
                        GVHotels.DataBind();
                    }
                }
            }
    
    

    So, how this works is that before we page, we have a routine to take the current page of data, and send it back to the persisted table - not back to the live database.

    First, our check all button - as noted, I assume all rows on all pages.

    Hence, this code:

            protected void chkAll_CheckedChanged(object sender, EventArgs e)
            {
                foreach (DataRow dRow in rstData.Rows)
                    dRow["Checked"] = true;
    
                GVHotels.DataSource = rstData;
                GVHotels.DataBind();
            }
    
    

    Note how I operate against the data table. So, the approch here was to think in terms of data - not really the UI.

    And our data pager code is this:

            protected void GVHotels_PageIndexChanging(object sender, GridViewPageEventArgs e)
            {
                // send data to table before page
                GridToTable();
                GVHotels.PageIndex = e.NewPageIndex;
                GVHotels.DataSource = rstData;
                GVHotels.DataBind();
            }
    
    

    So, all we do is "always" send the grid back to the persisted table with this code:

            void GridToTable()
            {
                // send grid rows back to table.
                foreach (GridViewRow rRow in GVHotels.Rows)
                {
                    int RecordPtr = rRow.DataItemIndex;
    
                    DataRow OneDataRow;
                    OneDataRow = rstData.Rows[RecordPtr];
                    OneDataRow["CustFeedBack"] = ((TextBox)rRow.FindControl("txtCustFeedBack")).Text;
                    OneDataRow["Checked"] = ((CheckBox)rRow.FindControl("ChkBox1")).Checked;
                }
            }
    
    

    So, that's about it. Our cancel button at the bottom can simply navagate back to some other page.

    Our save button will first save (send) the changes back to the database.

    That code is this:

            protected void cmdSave_Click(object sender, EventArgs e)
            {
                // send grid back to rstData
                GridToTable();
                // now send table back to database with updates
                string strSQL = "SELECT * from tblHotels";
                using (SqlCommand cmdSQL = new SqlCommand(strSQL,
                                            new SqlConnection(Properties.Settings.Default.TEST4)))
                {
                    cmdSQL.Connection.Open();
                    SqlDataAdapter daupdate = new SqlDataAdapter(cmdSQL);
                    SqlCommandBuilder cmdBuild = new SqlCommandBuilder(daupdate);
    
                    daupdate.Update(rstData);
                }
            }
    
    

    I should point out that the datatable in .net is rather smart, and with above, if you only modify 2 rows, then it will only generate 2 rows of update code back to sql server.

    Of course, after the above save, I would assume you then navigate to another page.

    I would suggest that the session that persisted the table be removed, but as above shows, the code is not all that complex. Note how the GridView row has 2 types of indexing into the data.

    RowIndex = row index of current page.

    DataItemIndex = index to the data source used for the GridView. So, this feature is quite much the Rossetta stone that makes all of this work.

    1 person found this answer helpful.

2 additional answers

Sort by: Most helpful
  1. Poluru Sairam Sekhar 31 Reputation points
    2024-05-18T04:57:18.0733333+00:00

    Hi @Gani_tpt,

    Maintaining GridView TextBox values during postbacks can be challenging, especially when paging is involved.

    Store the TextBox values in ViewState before the postback and retrieve them afterward.

    
    private void StoreValuesInViewState() {
    
      Dictionary<int, string> feedbacks = new Dictionary<int, string>();
    
      foreach (GridViewRow row in gvCustomer.Rows) {
    
        if (row.RowType == DataControlRowType.DataRow) {
    
          TextBox txtFeedback = row.FindControl("txtCustFeedback") as TextBox;
    
          if (txtFeedback != null) {
    
            int customerId =
    
                Convert.ToInt32(gvCustomer.DataKeys[row.RowIndex].Value);
    
            feedbacks[customerId] = txtFeedback.Text;
    
          }
    
        }
    
      }
    
      ViewState["Feedbacks"] = feedbacks;
    
    }
    
    private void LoadValuesFromViewState() {
    
      if (ViewState["Feedbacks"] != null) {
    
        Dictionary<int, string> feedbacks =
    
            (Dictionary<int, string>) ViewState["Feedbacks"];
    
        foreach (GridViewRow row in gvCustomer.Rows) {
    
          if (row.RowType == DataControlRowType.DataRow) {
    
            TextBox txtFeedback = row.FindControl("txtCustFeedback") as TextBox;
    
            if (txtFeedback != null) {
    
              int customerId =
    
                  Convert.ToInt32(gvCustomer.DataKeys[row.RowIndex].Value);
    
              if (feedbacks.ContainsKey(customerId)) {
    
                txtFeedback.Text = feedbacks[customerId];
    
              }
    
            }
    
          }
    
        }
    
      }
    
    }
    
    

    Call StoreValuesInViewState before any operation that causes a postback (e.g., paging, saving):

    
    protected void OnPaging(object sender, GridViewPageEventArgs e)
    
    {
    
      StoreValuesInViewState();
    
      gvCustomer.PageIndex = e.NewPageIndex;
    
      BindGrid();  // Method to bind the GridView with updated data
    
      LoadValuesFromViewState();
    
    }
    
    protected void btnSave_Click(object sender, EventArgs e)
    
    {
    
      StoreValuesInViewState();
    
      // Save data logic here
    
      LoadValuesFromViewState();
    
    }
    
    

    Like ViewState, Session can be used to store values. This approach is more suitable for larger data or when ViewState size becomes an issue.

    If the response helped, do "Accept Answer". If it doesn't work, please let us know the progress. All community members with similar issues will benefit by doing so. Your contribution is highly appreciated.


  2. AgaveJoe 26,851 Reputation points
    2024-05-19T13:05:01.41+00:00

    Your prior design fetched all the records which cause performance issues. You asked the community for help implementing custom paging to reduce the amount of records in the GridView. The GridView went from binding all the records to binding a page worth of records. This change effects the entire design approach. You, the developer, need to handle multiple post backs from the GridView.

    How about the OneIndexChanging handler? It fires for every time the GridView's page changes. Why not save the TextBox value in the OneIndexChanging handler? You already have the code in the button click handler.