views:

28

answers:

1

I am familiar with creating and persisting dynamic controls on the first load of a page and on subsequent postbacks but I am having trouble with the following user initiated scenario...

In my demo I have a placeholder, two buttons and a literal

<div>
    <asp:PlaceHolder ID="phResponses" runat="server" />
</div>
<div>
    <asp:Button ID="btnAdd" Text="Add" runat="server" OnClick="Add"/>
    <asp:Button ID="btnInspect" Text="Inspect" runat="server" OnClick="Inspect"/>
</div>
<div>
    <asp:Literal ID="litResult" runat="server"/>
</div>

I want the user to be able to click the add button to provide a response so I have...

protected void Page_Init(object sender, EventArgs e)
{
    BuildControls();
}

protected void Add(object sender, EventArgs e)
{
    BuildControls();
}

protected void BuildControls()
{
    phResponses.Controls.Add(new LiteralControl { ID = "response_" + _Count.ToString() });
    _Count++;
}

_Count is a static member variable to enable me to have unique ids for the new controls. I realise I need to rebuild the dynamic controls on Page_Init but the problem is that I end up with 2 new Literal controls on every postback. Also if any Text property is put into the new controls it is lost when the controls are rebuilt.

So how do I avoid adding multiple controls and how do I persist newly added properties when rebuilding these controls?

I use the following to inspect the responses

protected void Inspect(object sender, EventArgs e)
{
    foreach (var control in phResponses.Controls)
    {
        if (control is LiteralControl)
        {
            litResults.Text += "<p>" + control.Text + " : " + control.ID + "</p>";
        }
    }
}

Which itself adds another unwanted control because of the rebuilding on Page_Init

A: 

I'd not sure that I quite understand what you're asking, but it looks like you just want to ensure that BuildControls is only called once per lifecycle. You could do that by making the following changes:

  1. Add a new private bool _isControlsBuilt = false;.
  2. Change Page_Init to check _isControlsBuilt before calling BuildControls.
  3. Set _isControlsBuilt to true within BuildControls.
  4. Make sure that BuildControls occurs earlier in the page lifecycle than Page_Init.

As for losing the values of controls on postback, it'll be that they're never hitting the viewstate. I'm not sure if it'd work, but my first guess would be to add a line to the end of BuildControls to call Page.RegisterRequiresControlState:

protected void BuildControls()
{
    LiteralControl newLiteral = new LiteralControl { ID = "response_" + _Count };
    this.RegisterRequiresControlState(newLiteral);
    phResponses.Controls.Add(newLiteral);

    _Count++;
    _isControlsBuilt = true;
}

If that doesn't work (which might imply that it's the _view_state, not the _control_state that matters to you here), you may need to look at rolling your own viewstate. I wrote about how to do that in my answer to #3854193, which you might find useful.

Owen Blacker