View State issue with dynamically added controls-Plz help :-)

Discussion in 'ASP .Net' started by Chad, Jan 29, 2005.

  1. Chad

    Chad Guest

    I have a problem that I am desperate to understand.

    It involves dynamically adding controls to a Table control that is built as a result of performing a database query.

    I am not looking to avoid the problem by avoiding the table control or resorting to databound controls that better manage state for me. I hope to understand how to solve the problem by using the Table web control and sticking to the approach of building the table at run time rather than using databound controls.

    I tried to create the shortest code example that, when run, illustrates the problem.
    This is basically what I want to do:
    1) I want to query a table, Table1, which has two columns, "KeyCol" (PK int) and "Hide" (bit).
    2) I want to return all the rows where the Hide flag is not set to 1.
    3) For each returned row, I want to use the Table control to dynamically add a row to the Table for each record returned by the above query.
    4) For each TableRow created, I will add 2 TableCells (columns). The first column wil be display the KeyCol value returned.
    5) In the 2nd column, I will display a blank text box.
    6) If the user type ANY text in the text box and pushes the BUTTON at the bottom of the page, this will update the HIDE flag for the selected record in Table1.
    7) The display will then be refreshed. Since the query excludes recs where the Hide flag is set, this record will be removed from the table after the refresh,

    Now the problem....

    Everything works fine up to this point. But the next time that the user enters text in one of the remaining textboxes and pushes the BUTTON, the logic does not detect that there is any text in the text box! Howver, on the NEXT submit, the value will be detected!

    This is my understanding:

    In order to determine if a value was typed in the text box since the last submit, the table must be REBUILT each time. However, if the TABLE is redrawn (all rows removed and rebuilt), I think the view state is getting out of sync somehow (not sure!).

    I assume that the answer to this problem is just a tweek somewhere. Can someone help. I've spend too many hours on what should be a basic problem.

    Below is everything you should need to have a running example of what I am doing.

    I would be greatly appreciative to any help. Thanks

    ------------------------------------------------------------------------------------------------------------------
    CREATE TABLE [dbo].[Table1]
    (
    [KeyCol] [int] NOT NULL IDENTITY(1, 1),
    [Hide] [bit] NOT NULL
    )

    GO

    -- Constraints and indexes
    ALTER TABLE [dbo].[Table1] ADD CONSTRAINT [PK_Table1] PRIMARY KEY CLUSTERED ([KeyCol])
    GO

    BEGIN TRANSACTION
    SET IDENTITY_INSERT [dbo].[Table1] ON
    INSERT INTO [dbo].[Table1] ([KeyCol], [Hide]) VALUES (1, 0)
    INSERT INTO [dbo].[Table1] ([KeyCol], [Hide]) VALUES (2, 0)
    INSERT INTO [dbo].[Table1] ([KeyCol], [Hide]) VALUES (3, 0)
    INSERT INTO [dbo].[Table1] ([KeyCol], [Hide]) VALUES (4, 0)
    INSERT INTO [dbo].[Table1] ([KeyCol], [Hide]) VALUES (5, 0)
    INSERT INTO [dbo].[Table1] ([KeyCol], [Hide]) VALUES (6, 0)
    INSERT INTO [dbo].[Table1] ([KeyCol], [Hide]) VALUES (7, 0)
    SET IDENTITY_INSERT [dbo].[Table1] OFF
    COMMIT TRANSACTION
    -----------------------------------------------------------------------------
    Imports System.Web.UI.WebControls
    Imports System.Data.SqlClient

    Public Class WebForm1
    Inherits System.Web.UI.Page

    #Region " Web Form Designer Generated Code "

    'This call is required by the Web Form Designer.
    <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()

    End Sub
    Protected WithEvents Button1 As System.Web.UI.WebControls.Button
    Protected WithEvents Table1 As System.Web.UI.WebControls.Table

    'NOTE: The following placeholder declaration is required by the Web Form Designer.
    'Do not delete or move it.
    Private designerPlaceholderDeclaration As System.Object

    Private Sub Page_Init(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Init
    'CODEGEN: This method call is required by the Web Form Designer
    'Do not modify it using the code editor.
    InitializeComponent()
    End Sub

    #End Region

    Dim SqlConnection As SqlConnection

    Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

    SqlConnection = New SqlConnection("server=(local);database=skpirepository;uid=skpiuser;pwd=skpiuser")
    SqlConnection.Open()

    BuildTable()


    End Sub

    Private Sub BuildTable()

    Dim TableRow As TableRow
    Dim TableCell As TableCell
    Dim TextBox As TextBox
    Dim ds As New DataSet
    Dim DataRow As DataRow

    Dim SqlDataAdapter As New SqlDataAdapter("Select * from table1 where Hide <> 1", SqlConnection)

    SqlDataAdapter.Fill(ds, "table1")

    For Each DataRow In ds.Tables(0).Rows

    'Add Row
    TableRow = New TableRow
    Table1.Rows.Add(TableRow)

    'Add 1st Col Cell
    TableCell = New TableCell
    TableCell.Text = DataRow.Item("KeyCol").ToString
    TableRow.Cells.Add(TableCell)

    'Add 2nd Col TextBox
    TableCell = New TableCell
    TableRow.Cells.Add(TableCell)

    TextBox = New TextBox
    TableCell.Controls.Add(TextBox)

    Table1.Rows.Add(TableRow)

    Next

    End Sub

    Private Sub ClearRows()

    Dim r As Integer

    For r = Table1.Rows.Count - 1 To 0 Step -1
    Table1.Rows.Remove(Table1.Rows.Item(r))
    Next

    End Sub

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

    Dim TableRow As TableRow
    Dim TextBox As TextBox
    Dim KeyCol As Integer
    Dim RefreshTable As Boolean = False

    For Each TableRow In Table1.Rows

    KeyCol = CType(TableRow.Cells(0).Text, Integer)
    TextBox = CType(TableRow.Cells(1).Controls(0), TextBox)

    If Trim(TextBox.Text) <> "" Then
    Dim SqlCommand As New SqlCommand("UPDATE Table1 SET Hide = 1 WHERE KeyCol = " & KeyCol.ToString, SqlConnection)
    SqlCommand.ExecuteNonQuery()
    RefreshTable = True
    End If

    Next

    If RefreshTable Then
    ClearRows()
    BuildTable()
    End If

    End Sub

    End Class

    ----------------------------------------------------------------------------------------------------------
    <%@ Page Language="vb" AutoEventWireup="false" Codebehind="WebForm1.aspx.vb" Inherits="WebApplication2.WebForm1"%>
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
    <HTML>
    <HEAD>
    <title>WebForm1</title>
    <meta content="Microsoft Visual Studio .NET 7.1" name="GENERATOR">
    <meta content="Visual Basic .NET 7.1" name="CODE_LANGUAGE">
    <meta content="JavaScript" name="vs_defaultClientScript">
    <meta content="http://schemas.microsoft.com/intellisense/ie5" name="vs_targetSchema">
    </HEAD>
    <body>
    <form id="Form1" method="post" runat="server">
    <asp:table id="Table1" runat="server"></asp:table>
    <asp:button id="Button1" runat="server" Text="Type anything in the text box to remove that row"></asp:button></form>
    </body>
    </HTML>
     
    Chad, Jan 29, 2005
    #1
    1. Advertisements

  2. Chad

    Chad Guest

    I think I got the answer!

    I think I have the answer! Someone correct me if there is more to it than this:

    It appears that if I use assign an ID to the dynamically created controls, and reuse the same ID when I rebuild the controls, the ViewState syncs up!





    I have a problem that I am desperate to understand.

    It involves dynamically adding controls to a Table control that is built as a result of performing a database query.

    I am not looking to avoid the problem by avoiding the table control or resorting to databound controls that better manage state for me. I hope to understand how to solve the problem by using the Table web control and sticking to the approach of building the table at run time rather than using databound controls.

    I tried to create the shortest code example that, when run, illustrates the problem.
    This is basically what I want to do:
    1) I want to query a table, Table1, which has two columns, "KeyCol" (PK int) and "Hide" (bit).
    2) I want to return all the rows where the Hide flag is not set to 1.
    3) For each returned row, I want to use the Table control to dynamically add a row to the Table for each record returned by the above query.
    4) For each TableRow created, I will add 2 TableCells (columns). The first column wil be display the KeyCol value returned.
    5) In the 2nd column, I will display a blank text box.
    6) If the user type ANY text in the text box and pushes the BUTTON at the bottom of the page, this will update the HIDE flag for the selected record in Table1.
    7) The display will then be refreshed. Since the query excludes recs where the Hide flag is set, this record will be removed from the table after the refresh,

    Now the problem....

    Everything works fine up to this point. But the next time that the user enters text in one of the remaining textboxes and pushes the BUTTON, the logic does not detect that there is any text in the text box! Howver, on the NEXT submit, the value will be detected!

    This is my understanding:

    In order to determine if a value was typed in the text box since the last submit, the table must be REBUILT each time. However, if the TABLE is redrawn (all rows removed and rebuilt), I think the view state is getting out of sync somehow (not sure!).

    I assume that the answer to this problem is just a tweek somewhere. Can someone help. I've spend too many hours on what should be a basic problem.

    Below is everything you should need to have a running example of what I am doing.

    I would be greatly appreciative to any help. Thanks

    ------------------------------------------------------------------------------------------------------------------
    CREATE TABLE [dbo].[Table1]
    (
    [KeyCol] [int] NOT NULL IDENTITY(1, 1),
    [Hide] [bit] NOT NULL
    )

    GO

    -- Constraints and indexes
    ALTER TABLE [dbo].[Table1] ADD CONSTRAINT [PK_Table1] PRIMARY KEY CLUSTERED ([KeyCol])
    GO

    BEGIN TRANSACTION
    SET IDENTITY_INSERT [dbo].[Table1] ON
    INSERT INTO [dbo].[Table1] ([KeyCol], [Hide]) VALUES (1, 0)
    INSERT INTO [dbo].[Table1] ([KeyCol], [Hide]) VALUES (2, 0)
    INSERT INTO [dbo].[Table1] ([KeyCol], [Hide]) VALUES (3, 0)
    INSERT INTO [dbo].[Table1] ([KeyCol], [Hide]) VALUES (4, 0)
    INSERT INTO [dbo].[Table1] ([KeyCol], [Hide]) VALUES (5, 0)
    INSERT INTO [dbo].[Table1] ([KeyCol], [Hide]) VALUES (6, 0)
    INSERT INTO [dbo].[Table1] ([KeyCol], [Hide]) VALUES (7, 0)
    SET IDENTITY_INSERT [dbo].[Table1] OFF
    COMMIT TRANSACTION
    -----------------------------------------------------------------------------
    Imports System.Web.UI.WebControls
    Imports System.Data.SqlClient

    Public Class WebForm1
    Inherits System.Web.UI.Page

    #Region " Web Form Designer Generated Code "

    'This call is required by the Web Form Designer.
    <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()

    End Sub
    Protected WithEvents Button1 As System.Web.UI.WebControls.Button
    Protected WithEvents Table1 As System.Web.UI.WebControls.Table

    'NOTE: The following placeholder declaration is required by the Web Form Designer.
    'Do not delete or move it.
    Private designerPlaceholderDeclaration As System.Object

    Private Sub Page_Init(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Init
    'CODEGEN: This method call is required by the Web Form Designer
    'Do not modify it using the code editor.
    InitializeComponent()
    End Sub

    #End Region

    Dim SqlConnection As SqlConnection

    Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

    SqlConnection = New SqlConnection("server=(local);database=skpirepository;uid=skpiuser;pwd=skpiuser")
    SqlConnection.Open()

    BuildTable()


    End Sub

    Private Sub BuildTable()

    Dim TableRow As TableRow
    Dim TableCell As TableCell
    Dim TextBox As TextBox
    Dim ds As New DataSet
    Dim DataRow As DataRow

    Dim SqlDataAdapter As New SqlDataAdapter("Select * from table1 where Hide <> 1", SqlConnection)

    SqlDataAdapter.Fill(ds, "table1")

    For Each DataRow In ds.Tables(0).Rows

    'Add Row
    TableRow = New TableRow
    Table1.Rows.Add(TableRow)

    'Add 1st Col Cell
    TableCell = New TableCell
    TableCell.Text = DataRow.Item("KeyCol").ToString
    TableRow.Cells.Add(TableCell)

    'Add 2nd Col TextBox
    TableCell = New TableCell
    TableRow.Cells.Add(TableCell)

    TextBox = New TextBox
    TableCell.Controls.Add(TextBox)

    Table1.Rows.Add(TableRow)

    Next

    End Sub

    Private Sub ClearRows()

    Dim r As Integer

    For r = Table1.Rows.Count - 1 To 0 Step -1
    Table1.Rows.Remove(Table1.Rows.Item(r))
    Next

    End Sub

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

    Dim TableRow As TableRow
    Dim TextBox As TextBox
    Dim KeyCol As Integer
    Dim RefreshTable As Boolean = False

    For Each TableRow In Table1.Rows

    KeyCol = CType(TableRow.Cells(0).Text, Integer)
    TextBox = CType(TableRow.Cells(1).Controls(0), TextBox)

    If Trim(TextBox.Text) <> "" Then
    Dim SqlCommand As New SqlCommand("UPDATE Table1 SET Hide = 1 WHERE KeyCol = " & KeyCol.ToString, SqlConnection)
    SqlCommand.ExecuteNonQuery()
    RefreshTable = True
    End If

    Next

    If RefreshTable Then
    ClearRows()
    BuildTable()
    End If

    End Sub

    End Class

    ----------------------------------------------------------------------------------------------------------
    <%@ Page Language="vb" AutoEventWireup="false" Codebehind="WebForm1.aspx.vb" Inherits="WebApplication2.WebForm1"%>
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
    <HTML>
    <HEAD>
    <title>WebForm1</title>
    <meta content="Microsoft Visual Studio .NET 7.1" name="GENERATOR">
    <meta content="Visual Basic .NET 7.1" name="CODE_LANGUAGE">
    <meta content="JavaScript" name="vs_defaultClientScript">
    <meta content="http://schemas.microsoft.com/intellisense/ie5" name="vs_targetSchema">
    </HEAD>
    <body>
    <form id="Form1" method="post" runat="server">
    <asp:table id="Table1" runat="server"></asp:table>
    <asp:button id="Button1" runat="server" Text="Type anything in the text box to remove that row"></asp:button></form>
    </body>
    </HTML>
     
    Chad, Jan 29, 2005
    #2
    1. Advertisements

  3. Chad

    Karl Seguin Guest

    Chad:
    I didn't look at your question in any great detail..but what your saying makes a lot of sense...viewstate works by matching things in the Request.Form collection to controls based on their ID value...so if you aren't re-creating the controls with the right ID, then you'd likely see problems

    I realize you've solved your problem, but you might wanna take a look at: http://www.denisbauer.com/ASPNETControls/DynamicControlsPlaceholder.aspx which is a free control which aids in maintaining viewstate for dynamically created controls.

    Cheers,
    Karl

    --
    MY ASP.Net tutorials
    http://www.openmymind.net/


    I think I got the answer!

    I think I have the answer! Someone correct me if there is more to it than this:

    It appears that if I use assign an ID to the dynamically created controls, and reuse the same ID when I rebuild the controls, the ViewState syncs up!





    I have a problem that I am desperate to understand.

    It involves dynamically adding controls to a Table control that is built as a result of performing a database query.

    I am not looking to avoid the problem by avoiding the table control or resorting to databound controls that better manage state for me. I hope to understand how to solve the problem by using the Table web control and sticking to the approach of building the table at run time rather than using databound controls.

    I tried to create the shortest code example that, when run, illustrates the problem.
    This is basically what I want to do:
    1) I want to query a table, Table1, which has two columns, "KeyCol" (PK int) and "Hide" (bit).
    2) I want to return all the rows where the Hide flag is not set to 1.
    3) For each returned row, I want to use the Table control to dynamically add a row to the Table for each record returned by the above query.
    4) For each TableRow created, I will add 2 TableCells (columns). The first column wil be display the KeyCol value returned.
    5) In the 2nd column, I will display a blank text box.
    6) If the user type ANY text in the text box and pushes the BUTTON at the bottom of the page, this will update the HIDE flag for the selected record in Table1.
    7) The display will then be refreshed. Since the query excludes recs where the Hide flag is set, this record will be removed from the table after the refresh,

    Now the problem....

    Everything works fine up to this point. But the next time that the user enters text in one of the remaining textboxes and pushes the BUTTON, the logic does not detect that there is any text in the text box! Howver, on the NEXT submit, the value will be detected!

    This is my understanding:

    In order to determine if a value was typed in the text box since the last submit, the table must be REBUILT each time. However, if the TABLE is redrawn (all rows removed and rebuilt), I think the view state is getting out of sync somehow (not sure!).

    I assume that the answer to this problem is just a tweek somewhere. Can someone help. I've spend too many hours on what should be a basic problem.

    Below is everything you should need to have a running example of what I am doing.

    I would be greatly appreciative to any help. Thanks

    ------------------------------------------------------------------------------------------------------------------
    CREATE TABLE [dbo].[Table1]
    (
    [KeyCol] [int] NOT NULL IDENTITY(1, 1),
    [Hide] [bit] NOT NULL
    )

    GO

    -- Constraints and indexes
    ALTER TABLE [dbo].[Table1] ADD CONSTRAINT [PK_Table1] PRIMARY KEY CLUSTERED ([KeyCol])
    GO

    BEGIN TRANSACTION
    SET IDENTITY_INSERT [dbo].[Table1] ON
    INSERT INTO [dbo].[Table1] ([KeyCol], [Hide]) VALUES (1, 0)
    INSERT INTO [dbo].[Table1] ([KeyCol], [Hide]) VALUES (2, 0)
    INSERT INTO [dbo].[Table1] ([KeyCol], [Hide]) VALUES (3, 0)
    INSERT INTO [dbo].[Table1] ([KeyCol], [Hide]) VALUES (4, 0)
    INSERT INTO [dbo].[Table1] ([KeyCol], [Hide]) VALUES (5, 0)
    INSERT INTO [dbo].[Table1] ([KeyCol], [Hide]) VALUES (6, 0)
    INSERT INTO [dbo].[Table1] ([KeyCol], [Hide]) VALUES (7, 0)
    SET IDENTITY_INSERT [dbo].[Table1] OFF
    COMMIT TRANSACTION
    -----------------------------------------------------------------------------
    Imports System.Web.UI.WebControls
    Imports System.Data.SqlClient

    Public Class WebForm1
    Inherits System.Web.UI.Page

    #Region " Web Form Designer Generated Code "

    'This call is required by the Web Form Designer.
    <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()

    End Sub
    Protected WithEvents Button1 As System.Web.UI.WebControls.Button
    Protected WithEvents Table1 As System.Web.UI.WebControls.Table

    'NOTE: The following placeholder declaration is required by the Web Form Designer.
    'Do not delete or move it.
    Private designerPlaceholderDeclaration As System.Object

    Private Sub Page_Init(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Init
    'CODEGEN: This method call is required by the Web Form Designer
    'Do not modify it using the code editor.
    InitializeComponent()
    End Sub

    #End Region

    Dim SqlConnection As SqlConnection

    Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

    SqlConnection = New SqlConnection("server=(local);database=skpirepository;uid=skpiuser;pwd=skpiuser")
    SqlConnection.Open()

    BuildTable()


    End Sub

    Private Sub BuildTable()

    Dim TableRow As TableRow
    Dim TableCell As TableCell
    Dim TextBox As TextBox
    Dim ds As New DataSet
    Dim DataRow As DataRow

    Dim SqlDataAdapter As New SqlDataAdapter("Select * from table1 where Hide <> 1", SqlConnection)

    SqlDataAdapter.Fill(ds, "table1")

    For Each DataRow In ds.Tables(0).Rows

    'Add Row
    TableRow = New TableRow
    Table1.Rows.Add(TableRow)

    'Add 1st Col Cell
    TableCell = New TableCell
    TableCell.Text = DataRow.Item("KeyCol").ToString
    TableRow.Cells.Add(TableCell)

    'Add 2nd Col TextBox
    TableCell = New TableCell
    TableRow.Cells.Add(TableCell)

    TextBox = New TextBox
    TableCell.Controls.Add(TextBox)

    Table1.Rows.Add(TableRow)

    Next

    End Sub

    Private Sub ClearRows()

    Dim r As Integer

    For r = Table1.Rows.Count - 1 To 0 Step -1
    Table1.Rows.Remove(Table1.Rows.Item(r))
    Next

    End Sub

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

    Dim TableRow As TableRow
    Dim TextBox As TextBox
    Dim KeyCol As Integer
    Dim RefreshTable As Boolean = False

    For Each TableRow In Table1.Rows

    KeyCol = CType(TableRow.Cells(0).Text, Integer)
    TextBox = CType(TableRow.Cells(1).Controls(0), TextBox)

    If Trim(TextBox.Text) <> "" Then
    Dim SqlCommand As New SqlCommand("UPDATE Table1 SET Hide = 1 WHERE KeyCol = " & KeyCol.ToString, SqlConnection)
    SqlCommand.ExecuteNonQuery()
    RefreshTable = True
    End If

    Next

    If RefreshTable Then
    ClearRows()
    BuildTable()
    End If

    End Sub

    End Class

    ----------------------------------------------------------------------------------------------------------
    <%@ Page Language="vb" AutoEventWireup="false" Codebehind="WebForm1.aspx.vb" Inherits="WebApplication2.WebForm1"%>
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
    <HTML>
    <HEAD>
    <title>WebForm1</title>
    <meta content="Microsoft Visual Studio .NET 7.1" name="GENERATOR">
    <meta content="Visual Basic .NET 7.1" name="CODE_LANGUAGE">
    <meta content="JavaScript" name="vs_defaultClientScript">
    <meta content="http://schemas.microsoft.com/intellisense/ie5" name="vs_targetSchema">
    </HEAD>
    <body>
    <form id="Form1" method="post" runat="server">
    <asp:table id="Table1" runat="server"></asp:table>
    <asp:button id="Button1" runat="server" Text="Type anything in the text box to remove that row"></asp:button></form>
    </body>
    </HTML>
     
    Karl Seguin, Jan 29, 2005
    #3
    1. Advertisements

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.