Reputation: 204
I am having trouble getting the input values of dynamically created controls in a ListView.
Here is my ListView:
<asp:ListView ID="lvQuestions" runat="server" DataKeyNames="ProductQuestionId" onitemdatabound="lvQuestions_ItemDataBound">
<LayoutTemplate>
<table>
<tr runat="server" id="itemPlaceholder"></tr>
</table>
</LayoutTemplate>
<ItemTemplate>
<tr>
<td><%# Eval("Question") %></td>
<td>
<asp:PlaceHolder ID="plControl" runat="server" />
<asp:HiddenField ID="hfQuestionId" runat="server" />
</td>
</tr>
</ItemTemplate>
</asp:ListView>
<asp:Button ID="btnSubmit" runat="server" Text="Submit" onclick="btnSubmit_Click" />
In my ItemDataBound Handler I am adding a TextBox or other control to the Placeholder. The control type is dependent on the item, but to keep it simple lets assume it is always a Textbox. The ID of the control is also dynamic.
// create a textbox control
TextBox txtbx = new TextBox();
txtbx.ID = "txtQuestion_" + productQuestionId.ToString(); //productQuestionId is the datakey value of this ListViewItem
placeholder.Controls.Add(txtbx);
When a user clicks on the button I need to be able to get the values they filled out.
In my research I found that I need to first recreate the dynamically added controls in order to get the values of them due to the Page Lifecycle.
Here is what I have in my button handler to recreate the controls:
foreach (ListViewDataItem item in lvQuestions.Items)
{
HiddenField hdField = (HiddenField)item.FindControl("hfQuestionId");
PlaceHolder plcHolder = (PlaceHolder)item.FindControl("plControl");
TextBox txtbx = new TextBox();
txtbx.ID = "txtQuestion_" + hdField.Value;
plcHolder.Controls.Add(txtbx);
}
then the next block of code in the same handler I re-iterate through the ListViewDataItems and find the control:
foreach (ListViewDataItem item in lvQuestions.Items)
{
HiddenField hdField = (HiddenField)item.FindControl("hfQuestionId");
PlaceHolder plcHolder = (PlaceHolder)item.FindControl("plControl");
TextBox txtbx = (TextBox)plcHolder.FindControl("txtQuestion_" + hdField.Value);
if (txtbx != null)
{
Response.Write("TextBox Found:" + txtbx.Text);
}
}
The textbox is found, but there is no value. It's like I just wrote over the textboxes with new ones in the previous block. If I remove the previous block of code no textboxes are ever found.
Can someone please help me out with what I am missing here?
Thank you.
Upvotes: 4
Views: 5521
Reputation: 1
That didn't work for me, so I had to do this in the PreInit call
protected override void OnPreInit(EventArgs e)
{
base.OnPreInit(e);
foreach (ListViewDataItem item in lvQuestions.Items)
{
HiddenField hdField = (HiddenField)item.FindControl("hfQuestionId");
PlaceHolder plcHolder = (PlaceHolder)item.FindControl("plControl");
if (hdField != null && plcHolder != null)
{
TextBox txtbx = new TextBox();
txtbx.ID = "txtQuestion_" + hdField.Value;
plcHolder.Controls.Add(txtbx);
}
}
}
And I moved this method back to the ItemDataBound event
protected void lvQuestions_ItemDataBound(object sender, ListViewItemEventArgs e)
{
object datakey = lvQuestions.DataKeys[e.Item.DataItemIndex].Value; //get datakey here
TextBox txtbx = new TextBox();
txtbx.EnableViewState = true;
txtbx.ID = "txtQuestion_" + datakey.ToString(); //productQuestionId is the datakey value of this ListViewItem
PlaceHolder pl = e.Item.FindControl("plControl") as PlaceHolder;
HiddenField hf = e.Item.FindControl("hfQuestionId") as HiddenField;
if (pl != null)
pl.Controls.Add(txtbx);
if (hf != null)
hf.Value = datakey.ToString();
}
Then it started working.
Upvotes: 0
Reputation: 8421
As you've already discovered, this is a life cycle issue. Try creating your dynamic control in the ListView.ItemCreated event instead of the ListView.ItemDataBound event.
Upvotes: 3
Reputation: 14447
I think the issue here is that the lifecycle does not have a chance to populate the controls with their submitted values before you are trying to read those values.
Typically, if I was going to do something like this, I would be recreating the controls in the Page_Init event, which happens before the values are loaded into the controls. You could potentially do this in a particular control's Init event also, but that is where the additional controls need to be re-added to the page.
Upvotes: 1