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

C

Chad

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>
 
C

Chad

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>
 
K

Karl Seguin

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>
 

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. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,982
Messages
2,570,185
Members
46,736
Latest member
AdolphBig6

Latest Threads

Top