3
votes

I'm brand-new to ASP.NET, so bear with me.

Here's a simplified explanation of my scenario. I have a button on a page. When I click the button, I'm retrieving a list of strings from a database and dynamically generating a series of link buttons with the retrieved strings as the Text of the link buttons.

I already understand that I can't do this in the button's click event handler for several reasons. I also understand that dynamic controls need to be generated in the Page_Init or Page_Load event handlers so that the link buttons' click events can be wired up.

So, here's the process I considered:

  1. Click the button
  2. In the click event handler, retrieve the strings and store them in a ViewState variable
  3. In the Page_Load event handler, iterate through the strings in the ViewState variable and generate the link buttons

Here's the problem: because of the page's life cycle, the button's click event isn't dealt with until AFTER the Page_Load event. As such, the strings I use to generate the link buttons aren't retrieved and assigned to the ViewState variable until AFTER the Page_Load event (where I was hoping to create the link buttons).

As such, the link buttons aren't generated until the SECOND click of the button, when the ViewState variable has been assigned. Obviously, this is a problem.

The solution I devised works, but I don't know if it's the optimal solution. Here's the method I'm using:

  1. Click the button
  2. Page_Load event fires
  3. In the Page_Load event handler, if it's a PostBack check to see if the ViewState variable is null and which control triggered the PostBack
  4. If the ViewState variable is null and The Button was clicked, retrieve the strings, save them to the ViewState variable, and generate the link buttons based on the ViewState variable
  5. If the ViewState variable is not null, generate the link buttons based on the ViewState variable

Now, this solution actually works. However, if I refresh the page, I get the Confirm Form Resubmission pop-up (which I don't like, but I can live with).

My question to the pro-coders on here is -- how would you have handled my situation?

UPDATE:

Here's a solution that seems to work. I may have been confused about where event handlers can be wired up, but please take a look at this code and tell me if it makes sense or if it's just a hack:

public partial class _Default : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        if (IsPostBack)
        {
            if(ViewState["ControlsArray"] != null)
            {
                ArrayList controlsList = (ArrayList)ViewState["ControlsArray"];
                GenerateLinkButtons(controlsList);
            }
        }
    }

    //The event handler for the dynamically generated linkbuttons
    void linkButton_Click(object sender, EventArgs e)
    {
        LinkButton btn = (LinkButton)sender;
        string btnName = btn.Text;

        Response.Write(btnName);
    }

    //The click event handler for the Generate Controls button
    protected void Button1_Click(object sender, EventArgs e)
    {
        ArrayList PageArrayList = new ArrayList();

        PageArrayList = new ArrayList();
        PageArrayList.Add("Text 1");
        PageArrayList.Add("Text 2");
        PageArrayList.Add("Text 3");
        PageArrayList.Add("Text 4");
        PageArrayList.Add("Text 5");

        GenerateLinkButtons(PageArrayList);

        ViewState["ControlsArray"] = PageArrayList;
    }

    void GenerateLinkButtons(ArrayList controlsList)
    {
        int i = 1;

        foreach (string s in controlsList)
        {
            LinkButton lnkButton = new LinkButton();
            lnkButton.ID = "btn" + i;
            lnkButton.Text = s;
            this.form1.Controls.Add(lnkButton);
            this.form1.Controls.Add(new LiteralControl("<br />"));
            lnkButton.Click += new EventHandler(linkButton_Click);
            i++;
        }
    }
}
1
Why aren't you generating the linkbuttons directly in the button click's event handler, you shouldn't have the code to retrieve the string from the DB there for separation of concerns' sake, but UI interactions like generating buttons are correct.Axel
Sure, but my understanding was that you couldn't wire up event handlers for the newly added controls in that click event handler. That has to be done in the Page_Init or Page_Load event handlers.Jeremy Choate
As Mt.Scheniders said in his response, I don't thinks so either.Axel

1 Answers

2
votes

dynamic controls need to be generated in the Page_Init or Page_Load event handlers so that the link buttons' click events can be wired up.

Actually, You can create controls on the Button Click event. But you have to make sure these controls are recreated in the following PostBacks.

So let's say you have a property called Data that points to a ViewState variable. Let's also assume that you are using a Repeater to create the LinkButtons.

Then you could do something like this:

private List<string> Data
{
    get { return (List<string>)ViewState["Data"]; }
    set { ViewState["Data"] = value; }
}

protected void Button_Click(object sender, EventArgs e)
{
    Data = GetData();
    LoadRepeater();
}

protected void Page_Load(object sender, EventArgs e)
{
    if(Data != null)
    {
        LoadRepeater();
    }
}

private void LoadRepeater()
{
    repeater.DataSource = Data;
    repeater.DataBind();
}

Repeater:

<asp:Repeater id="repeater" runat="server">
    <ItemTemplate>
        <asp:LinkButton id="link" runat="server" OnClick="link_Click" />
    </ItemTemplate>
</asp:Repeater>

protected void link_Click(object sender, EventArgs e)
{
    //Do Stuff
}

Additionally, if you want to avoid the Confirm Form Resubmission, use the ASP.NET UpdatePanel control. Example:

<asp:UpdatePanel id="upp" runat="server" >
    <ContentTemplate>
        <!-- Button-->
        <!-- Repeater-->
        <!-- Other Stuff-->
    </ContentTemplate>
</asp:UpdatePanel>

Another approach (not sure if it works):

Try setting the repeater DataSource on the Tag Definition:

<asp:Repeater id="repeater" runat="server" DataSource='<%# Data %>' >
    <ItemTemplate>
        <asp:LinkButton id="link" runat="server" OnClick="link_Click" />
    </ItemTemplate>
</asp:Repeater>

protected void Button_Click(object sender, EventArgs e)
{
    Data = GetData();
    LoadRepeater();
}

protected void Page_Load(object sender, EventArgs e)
{
}

private void LoadRepeater()
{
    repeater.DataBind();
}