0

I have a GridView with several TextBox TemplateFields. When a value is entered into one of them, I want to postback, update one of the SQL Tables that it's pulling data from, then pull that new value into the GridView after the postback. In the markup I have:

<asp:BoundField DataField = "AtmId" HeaderText ="Atm Id"/>
<asp:TemplateField HeaderText ="Cassette 2 $">
        <ItemTemplate>
                 <asp:TextBox ID="Cassette2" OnTextChanged="Cassette2_TextChanged" runat="server" Text="" AutoPostBack ="true"></asp:TextBox>
        </ItemTemplate>
</asp:TemplateField>

Then in the code behind when text is written

protected void Page_Load(object sender, EventArgs e) 
{  
RoutesTableAdapter adapter = new RoutesTableAdapter(); 
DataTable dt = adapter.GetDataBy(148);  
System.Diagnostics.Debug.WriteLine(adapter.GetDataBy(148).Rows[0]["Cassette 2  $"]);  
if (!IsPostBack) 
{ 
GridView1.DataSource = dt; 
GridView1.DataBind(); 
for (int j = 0; j < GridView1.Rows.Count; j++) { 
GridViewRow row = GridView1.Rows[j]; 
TextBox Cass2 = row.FindControl("Cassette2") as TextBox; 
Cass2.Text = dt.Rows[j]["Cassette 2 $"].ToString(); 
Cass2.ReadOnly = false; 
} }
protected void Cassette2_TextChanged(object sender, EventArgs e)
{
try
{
    TextBox txt = sender as TextBox;
    GridViewRow row = txt.NamingContainer as GridViewRow;
    RoutesTableAdapter adapter = new RoutesTableAdapter();
    int AtmId = int.Parse(row.Cells[0].Text);
    adapter.UpdateCass2(int.Parse(txt.Text), AtmId);
}catch(Exception exc)
{
     txt.Text = "0";
}
}

In Page_Load, regardless of if it's on postback or not, new RoutesTableAdapter().GetData() will give a table with values that don't contain the changes made. I can print out a line and view that same line in SSMS, and they don't match until the page is refreshed. I thought this might be intended behavior, but everywhere I've ready online makes it seem like it's not supposed to need a refresh to update. Most other questions with this problem that I've seen had to do with the DataSet TableAdapters being pointed to a different database, but there's only one DB on the server with this data, and once the page is refreshed they agree. For additional context, the SQL statements are:

CREATE PROCEDURE [dbo].UpdateCass2
(
    @Cass2 int,
    @AtmId int
)
AS
    SET NOCOUNT OFF;
UPDATE ForecastRoute SET Cass2 = @Cass2 WHERE AtmId = @AtmId

And GetDataBy() is:

SELECT AtmId, Cass2 AS [Cassette 2 $] FROM ForecastRoute WHERE AtmId = @AtmId

I'm able to see immediately any changes in Cass2 after postback in SSMS, using the exact query for GetDataBy(), but the debug output still writes the old value. I thought maybe DataSet did something that I don't understand, like making an intermediate table with the schema defined in the SELECT statement, but that wouldn't explain why changes are reflected in SSMS immediately, right?

Edit: minimum reproducible example including page_load. There are other columns in the table and other tables that it's pulling from, but for just a ForecastRoute table with two columns and a row where AtmId = 148 I'd expect to be able to see the changes immediately, but I'm still only able to see it in SSMS.

MRoads
  • 1
  • 1
  • 1
    You need to provide a [mcve]. It's not enough to describe how GetData is called, but you must actually provide an example showing it being called, show where you perform the databinding etc. – mason Apr 12 '21 at 20:36
  • Thanks for the response, I edited in my page_load where the data is pulled from SQL then bound. GetDataBy is the same as the GetData posted earlier, with `AND AtmId = @AtmId` tacked on to the WHERE clause. – MRoads Apr 12 '21 at 20:56
  • You are re-binding and re-loading the grid again, and doing so before you pull out any updated values. Re-bind and re-load of the gv will blow out your changes you made. You need to get/grab/save and deal with the changes made to Cassette2 BEFORE you re-load the grid. You simply can't re-bind and thus re-load the grid and THEN hope to pull values out AFTER the re-bind. You have to update the table first and before you re-bind and re-load the grid again. So you have to re-load the grid after table changes, but you must grab + save the changes before you do so. – Albert D. Kallal Apr 12 '21 at 21:39
  • You thus could in theory move the datasource + bind AFTER that loop. As such, the data would not be save back to the table, but you would at least be grabbing the values from the grid and shoving them into the table before you bind that table to the grid. – Albert D. Kallal Apr 12 '21 at 21:46
  • I'm confused, there's no rebinding happening as far as I'm aware. We only bind anything to the GridView on the first load, everything after isn't executed on postback. We know that the changes have been made, since we can look at the database in SSMS. Theoretically we should have `Cass2.Text = dt.Rows[0]["Cassette 2 $"].ToString();` outside of the postback to actually reflect the change in the database in the GridView, but the problem is that the value of Cassette 2 $ in the datatable isn't equal to its value in the database immediately after querying it. I'm not worried about the GridView. – MRoads Apr 12 '21 at 22:43
  • Looks like textChanged events fire after the page_load, I probably should have known that. It's already posted back and is checking to see if the two values are different before it can fire an event, so it would be weird if the textChanged happened first. I simplified it down to just a text box and was able to get it to lag behind the DB, which is what we should expect. There's probably something in the actual code that's overwriting even that. Thanks for the responses. – MRoads Apr 12 '21 at 23:06
  • yes, there is a re-bind right in the on-load event. You do a re-bind RIGHT before you running the loop to pull the grid values . Clear as day! You have to move the gv bind AFTER that loop. A re-bind of the gv blows it out and you lose all your changes. So, you can't re-load and re-bind the gv, and THEN run that loop. Your posted code MOST certainly as CLEAR AS DAY does a re-bind of the gv, and THEN runs a loop trying to pull values from the gv (that we just re-loaded and lost all our changes to!!!). Move your re-bind of the gv to AFTER THAT loop, and you find/see that your values exist. – Albert D. Kallal Apr 13 '21 at 18:38

1 Answers1

0

Looks like textChanged events fire after the page_load, I probably should have known that. It's already posted back and is checking to see if the two values are different before it can fire an event, so it would be weird if the textChanged happened first. I simplified it down to just a text box and was able to get it to lag behind the DB, which is what we should expect. There's probably something in the actual code that's overwriting even that. Thanks for the responses.

MRoads
  • 1
  • 1
  • Just put the first load up of the grid in the page load event inside - if postback = False. This should be done for all pages that load up controls/grid. Then additonal buttons, post backs etc. will not re-load the grid. As noted, you could move the databind below your loop, and pull the grid values into the table, update and then re-bind. But then again, this code stub should be seperate - and in the else for post back code that runs by your design. So, as a general rule, load up grids, combo boxes etc. in the first page load only (postback = false). – Albert D. Kallal Apr 12 '21 at 23:20