Vishal
Vishal

Reputation: 6368

value of variables not changing in asp.net

currently I am working on a project named online exam. All the controls are dynamically created.

I have a webpage where I want to display the student details. I displayed those details correctly in a table. Now here comes the time to edit those details. To edit a record I use the linked button named edit. When a user clicks on that Linked button the data in that row is replaced with new textboxes. Upto here I am OK. Now when I click on the save changes button after making changes to the textboxes. The old values are not replaced by the new values and the old values remains.

The code for creating textboxes in the table is as follows :

Public Sub Edit_Click(ByVal sender As Object, ByVal e As System.EventArgs)

        For x As Integer = 0 To EditList.Count - 1

            If sender.id.substring(4) = EditList(x).ID.Substring(4) Then

                Session("PreviousRollNo") = RollNoList(x).Text

                Dim txtName As New TextBox
                txtName.Text = NameList(x).Text
                NameList(x).Text = ""
                NameList(x).Parent.Controls.Add(txtName)
                txtList.Add(txtName)

                Dim txtCourse As New TextBox
                txtCourse.Text = CourseList(x).Text
                CourseList(x).Text = ""
                CourseList(x).Parent.Controls.Add(txtCourse)
                txtList.Add(txtCourse)

                Dim txtAdmissionDate As New TextBox
                txtAdmissionDate.Text = AdmissionList(x).Text
                AdmissionList(x).Text = ""
                AdmissionList(x).Parent.Controls.Add(txtAdmissionDate)
                txtList.Add(txtAdmissionDate)

                Dim btnSaveChanges As New Button
                btnSaveChanges.Text = "Save Changes"
                EditList(x).Text = ""
                EditList(x).Parent.Controls.Add(btnSaveChanges)
                AddHandler btnSaveChanges.Click, AddressOf btnSaveChanges_Click
                Session("EditButtonClicked") = True

                Dim btnCancel As New Button
                btnCancel.Text = "Cancel"
                DeleteList(x).Text = ""
                DeleteList(x).Parent.Controls.Add(btnCancel)
                AddHandler btnCancel.Click, AddressOf btnCancel_Click
                Session("CancelButtonClicked") = True

                txtName.Focus()

                Exit For

            End If

        Next

    End Sub

The code for Save Changes button is as follows :

Public Sub btnSaveChanges_Click(ByVal sender As Object, ByVal e As System.EventArgs)

        If txtList(0).Text = "" Then

            Dim trError As TableRow = New TableRow

            Dim tdError As TableCell = New TableCell
            tdError.ColumnSpan = 7

            Dim lblError As New Label
            lblError.Text = "Please enter name of the student."
            lblError.ForeColor = Drawing.Color.Red
            tdError.Controls.Add(lblError)

            trError.Controls.Add(tdError)

            tbl.Controls.Add(trError)

        ElseIf txtList(1).Text = "" Then

            Dim trError As TableRow = New TableRow

            Dim tdError As TableCell = New TableCell
            tdError.ColumnSpan = 7

            Dim lblError As New Label
            lblError.Text = "Please enter the course."
            lblError.ForeColor = Drawing.Color.Red
            tdError.Controls.Add(lblError)

            trError.Controls.Add(tdError)

            tbl.Controls.Add(trError)

        ElseIf txtList(2).Text = "" Then

            Dim trError As TableRow = New TableRow

            Dim tdError As TableCell = New TableCell
            tdError.ColumnSpan = 7

            Dim lblError As New Label
            lblError.Text = "Please enter the Admission Date"
            lblError.ForeColor = Drawing.Color.Red
            tdError.Controls.Add(lblError)

            trError.Controls.Add(tdError)

            tbl.Controls.Add(trError)

        Else

            Dim cb As New OleDbCommandBuilder(da)

            Dim editRow() As DataRow

            editRow = ds.Tables("Student_Detail").Select("Roll_No = '" & Session("PreviousRollNo") & "'")

            editRow(0)("Name") = txtList(0).Text
            editRow(0)("Course") = txtList(1).Text
            editRow(0)("Admission_Date") = txtList(2).Text

            da.Update(ds, "Student_Detail")

            Page.Response.Redirect("ChangeUserDetails.aspx")

        End If

    End Sub

I get the error sying that array is out of the bounds. on the first line of the btnSaveChanges_Click. It means txtlist is always cleared when I click on Save Changes Button. So I stored txtList in a Session like Session("txtList") = txtList. and retrieved the data from that. But now I get the old values of the textbox instead of the newer ones. Here txtList is a list (of Textbox)

Upvotes: 1

Views: 1311

Answers (1)

Snixtor
Snixtor

Reputation: 4297

Firstly, welcome to the ASP.NET WebForms Page Life Cycle. Remember its pattern with the simple mnemonic: SILVER = Start, Init, Load, Validate, Events, Render.

Secondly, HTTP is stateless. WebForms does an amazing job of hiding this fact from you using ViewState until you do something a little out of the ordinary (as you're now attempting), and it all appears to fall apart. What's really happening is that you're starting to see side-effects of how WebForms is managed, and how it's not as much like WinForms (or another stateful system) as you might think.

When you're responding to an event server-side in WebForms, it's easy to get the impression that nothing has changed. That the entire page is as you left it "last time". All the controls are there, the values you may have set programatically are still set. Magic. Not magic. What's actually happened is the entire page has been re-constructed to respond to that event. How was it re-constructed? By a combination of your page definition (markup), actions taken in control event handlers, and the form data posted back by the client.

Confusing? OK, let's consider an example. Say you've got a page with two controls on it. A textbox named txtInput and a button named btnSubmit with event handler btnSubmit_Click. When the user first requests the page, the HTML for these controls is derived from your markup (aspx page) and returned to the client. Next, the user sets a value in txtInput and clicks the submit button. The server then re-creates the page from scratch based on your markup. At this early stage of the life-cycle, the controls still have their default values. We then hit the Load stage of the life-cycle, and "if the current request is a postback, control properties are loaded with information recovered from view state and control state." In other words, by the time the life-cycle gets to Init, the control has been created from markup, but still has its default value. The Load stage then sets the value according to Postback data.

Left wondering how this applies to your scenario? You're adding your dynamic controls in response to a control event. There's two things wrong with that:

  1. It's too late in the page life-cycle for Init to set the values based on data posted back from the client (recall SILVER, Event is after Init).
  2. Your button click event handler is only run once, in response to the postback where the user clicked the button. But remember on each postback the page is entirely re-created. So the dynamic controls no longer exist as far as the server is concerned! You'll notice that not only are the controls not present server side when responding to the submit event, but after the page has handled it, they're no longer present client-side either.

So what's the answer? Well the "Life-Cycle Events" section of the page I linked offers a clue. It states that the PreInit event be used to (among other things) "Create or re-create dynamic controls". Why would we do it in PreInit? So it's early enough in the page life-cycle for the later events to properly handle it (like setting the values posted back from the client).

Now, I know, you want to add the controls based on the user clicking on the button. How does that fit? The trick is that you've got to manage the "state" yourself. Huh? the state? By this I mean MyDynamicControlsShouldBeShown = true / false. When the button is clicked, creating the controls in response to the button-click event handler is the right action (there's not really any choice there). But you need to store that state somehow so you know on subsequent requests to the page, whether those controls should be re-created in PreInit. One neat option would be to check for the ID of your dynamic control in Request.Form.Keys. If the control ID is present in the Keys collection, then the user is posting back a value for the control, so you should re-create it.


A side-note on the use of Session

Hopefully based on the above you've realised why putting the controls into Session didn't work. But to be clear, the controls you put into the Session object were no longer part of a page that existed (remember, the page gets completely re-created for each request. Those controls were no longer hooked up to the Page events, so didn't get their values populated between Page Init and Load. If somehow it did work, it still wouldn't be a particularly good idea, as Session is not per-request. So what would happen if a user had the same page open in multiple tabs? Strange things, that's what.

Upvotes: 3

Related Questions