I have a page that contains some dynamically created controls (TextBox and DropDownList). When a postback occurs, the TextBoxes keep their values, but the DropDownLists lose their ListItems.
This is quite confusing, since the page level DropDownList also keeps its ListItems. Can anyone see what's wrong with the code below?
Any help in solving this issue would be greatly appreciated.
<%@ Page Language="VB"%>
<script runat="server">
Protected Sub Page_Init(ByVal sender As Object, ByVal e As System.EventArgs)
If Not Page.IsPostBack Then
ddlFixed.Items.Add(New ListItem("12", "13"))
ddlFixed.Items.Add(New ListItem("14", "15"))
End If
Dim i As Integer
For i = 0 To 3
Dim ddl As New DropDownList
ddl.ID = "ddlPage" & i
ddl.EnableViewState = True
If Not Page.IsPostBack Then
ddl.Items.Add(New ListItem("12", "13"))
ddl.Items.Add(New ListItem("14", "15"))
End If
pnlDynamic.Controls.Add(ddl)
Dim txtBx As New TextBox
txtBx.ID = "txtPage" & i
If Not Page.IsPostBack Then
txtBx.Text = "Preset"
End If
pnlDynamic.Controls.Add(txtBx)
Next
End Sub
</script>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server" enableviewstate="true">
<div>
<br />
<br />
<a href="Default.aspx">Get-Request</a>
<br />
<br />
<asp:Panel runat="server" ID="pnlDynamic" EnableViewState="true" />
<br />
<br />
<asp:DropDownList runat="server" ID="ddlFixed" />
<asp:Button runat="server" ID="btn" Text="Postback"/>
</div>
</form>
</body>
</html>
I have found the solution that will allow me to keep the viewstate across postbacks.
It's to call TrackViewState of the ItemCollection.
CType(ddl.Items, IStateManager).TrackViewState()
Thanks to all for your help.
This is the working solution:
<%@ Page Language="VB"%>
<script runat="server">
Protected Sub Page_Init(ByVal sender As Object, ByVal e As System.EventArgs)
If Not Page.IsPostBack Then
ddlFixed.Items.Add(New ListItem("12", "13"))
ddlFixed.Items.Add(New ListItem("14", "15"))
End If
Dim i As Integer
For i = 0 To 3
Dim ddl As New DropDownList
ddl.ID = "ddlPage" & i
CType(ddl.Items, IStateManager).TrackViewState()
If Not Page.IsPostBack Then
ddl.Items.Add(New ListItem("12", "13"))
ddl.Items.Add(New ListItem("14", "15"))
End If
pnlDynamic.Controls.Add(ddl)
Dim txtBx As New TextBox
txtBx.ID = "txtPage" & i
If Not Page.IsPostBack Then
txtBx.Text = "Preset"
End If
pnlDynamic.Controls.Add(txtBx)
Next
End Sub
</script>
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server" >
<div>
<br />
<br />
<a href="Default.aspx">Get-Request</a>
<br />
<br />
<asp:Panel runat="server" ID="pnlDynamic" />
<br />
<br />
<asp:DropDownList runat="server" ID="ddlFixed" />
<asp:Button runat="server" ID="btn" Text="Postback"/>
</div>
</form>
</body>
</html>
A DDL will maintain its items and selection when viewstate is enabled. A textbox will maintain its contents regardless of viewstate since the resulting html is written back to the server on a postback.
I find it courious that you have all these viewstate statements in your code and markup.
One of several things is happening:
- ViewState at the control is disabled
- ViewState above the contrl hierachy is disabled (page, form, panel)
- You are dynamically adding the control too late in the page cycle for the selection to be loaded from viewstate. Loading in INIT should be fine.
May be you need to explicitly activate the ViewState for those DropDownLists...
EDIT: This is what I mean by my last comment...
<script runat="server">
Protected Sub Page_Init(ByVal sender As Object, ByVal e As System.EventArgs)
If Not Page.IsPostBack Then
ddlFixed.Items.Add(New ListItem("12", "13"))
ddlFixed.Items.Add(New ListItem("14", "15"))
Dim i As Integer
For i = 0 To 3
Dim ddl As New DropDownList
ddl.ID = "ddlPage" & i
ddl.EnableViewState = True
ddl.Items.Add(New ListItem("12", "13"))
ddl.Items.Add(New ListItem("14", "15"))
pnlDynamic.Controls.Add(ddl)
Dim txtBx As New TextBox
txtBx.ID = "txtPage" & i
txtBx.Text = "Preset"
pnlDynamic.Controls.Add(txtBx)
Next
End If
End Sub
</script>
I always use Page_Load
and never have trouble like this. Maybe something you could look at.
I generally bind data to controls the first time the page loads, and after that let Viewstate handle postbacks etc. Note that they suggest you bind data during Page_Load
...
Check out http://support.microsoft.com/kb/305141
Page Events
loadTOCNode(2, 'moreinformation');
During the life cycle of an ASP.NET page, a few standard events
that are exposed from the Page object are used frequently. The ASP.NET page framework
automatically connects to (or wires up) appropriate delegate instances at run
time for these methods. This saves you from having to write the necessary "glue
code." The following list presents the delegate instances that are wired up at
run time in the order in which they are fired:
- Page_Init: During this event, you can initialize values or connect any
event handlers that you may have.
- Page_Load: During this event, you can perform a series of actions to either
create your ASP.NET page for the first time or respond to client-side events
that result from a post. The page and control view state have been restored
prior to this event. Use the IsPostBack page property to check whether this is the first time that the
page is being processed. If it is the first time, perform data binding. Also,
read and update control properties.
- Page_DataBind: The DataBind event is raised when the DataBind method is called at the page level. If you call DataBind on individual controls, it only fires the DataBind event of the controls beneath it.
- Page_PreRender: The PreRender event is fired just before the view state is saved and the
controls are rendered. You can use this event to perform any last minute
operations on your controls.
- Page_Unload: After a page has finished rendering, the Page_Unload event fires. This event is a good place to perform final cleanup
work. This includes items such as the cleanup of open database connections,
discarding objects, or closing those files that are open.
The following list outlines the events that are
non-deterministic:
- Page_Error: If an unhandled exception occurs during page processing, the Error event fires. The Error event gives you an opportunity to gracefully handle
errors.
- Page_AbortTransaction: Transaction events are useful if you want to indicate whether a transaction
succeeds or fails. This event is commonly used for shopping cart scenarios in
which this event can indicate the success or failure of an order. This event
fires when a transaction has been aborted.
- Page_CommitTransaction: This event fires when a transaction has been committed
successfully.
The list items in a DropDownList are not stored in view state. You'll have to add them on every postback.
What's stored in view state is the selected index - ie. the 'value' of the control.
Edit: Well, it seems I learned something today. I stand corrected :-)