Dukebaby
Dukebaby

Reputation: 204

Get values of dynamically added controls in ListView

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

Answers (3)

user1840055
user1840055

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

Phaedrus
Phaedrus

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

Andrew
Andrew

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

Related Questions