Dynamically loading and adding usercontrols after CreateChildControls

Discussion in 'ASP .Net Building Controls' started by Hendrik W. Hansen, May 28, 2004.

  1. Hi,

    I'm having a problem with loading and adding usercontrols dynamically after
    CreateChildControls. To be more specific, I have a number of buttons and a
    PlaceHolder control. When the user clicks one of the buttons, I want to load
    and add a different usercontrol in the click event handler, which of course
    occurs after CreateChildControls. In the eventhandler I also write a value
    to ViewState, so that I can read that value in the override of
    CreateChildControls after a postback and load the proper usercontrol.

    It works fine the first time the user clicks a button, and the placeholder
    does not contain any controls. However if a control was already loaded in
    the CreateChildControls, because it existed before the postback, and I
    remove that control and add a new one in the click eventhandler, the events
    of the new control does not seem to work in the following postback. Only
    after the second postback, the events are working. It seems that if a
    control has already been loaded into that position in the controls
    collection in the CreateChildControls, a new control loaded and added to
    that position is not able register its events to work in the next postback -
    don't know if it has something to do with the ViewState of that position has
    already been "taken" by another. After the first postback the control is
    loaded in the CreateChildControls - the events will not fire, since they did
    not get registered properly, but since no control has existed in that
    position in the controls collection before in the page cycle, the events
    gets registered properly this time. After the second postback, the events
    fire as planned.

    I could make an if control block in CreateChildControls, that prevented a
    control from being loaded into the placeholder, if a control was going to be
    loaded at a later stage in a click eventhandler. The problem is that there
    is no way of knowing whether a button has been clicked in the
    CreateChildControls - this is only possible to know in the eventhandler, and
    at that point it's too late, a control has already been loaded into the
    position, and events will not work.

    Is it really possible, that controls cannot be loaded and added to a
    controls collection after CreateChildControls, if they contain postback
    eventhandlers? Please let me know if anyone has a solution to this problem..

    Here is a sample of my code:

    public class WebForm1 : System.Web.UI.Page
    {
    protected System.Web.UI.WebControls.Button load1Btn;
    protected System.Web.UI.WebControls.PlaceHolder placeHolder;
    protected System.Web.UI.WebControls.Button load2Btn;

    override protected void OnInit(EventArgs e)
    {
    load1Btn.Click += new EventHandler(load1Btn_Click);
    load2Btn.Click += new EventHandler(load2Btn_Click);
    }

    protected override void CreateChildControls()
    {
    if (ViewState["loadedControl"] is string)
    placeHolder.Controls.Add(LoadControl((string)
    ViewState["loadedControl"]));
    base.CreateChildControls();
    }

    private void load1Btn_Click(object sender, EventArgs e)
    {
    ViewState["loadedControl"] = "DynamicControl1.ascx";
    if (placeHolder.Controls.Count > 0)
    placeHolder.Controls.RemoveAt(0);
    placeHolder.Controls.Add(LoadControl("DynamicControl1.ascx"));
    }

    private void load2Btn_Click(object sender, EventArgs e)
    {
    ViewState["loadedControl"] = "DynamicControl2.ascx";
    if (placeHolder.Controls.Count > 0)
    placeHolder.Controls.RemoveAt(0);
    placeHolder.Controls.Add(LoadControl("DynamicControl2.ascx"));
    }
    }

    public class DynamicControl1 : System.Web.UI.UserControl
    {
    protected System.Web.UI.WebControls.Label msgLbl;
    protected System.Web.UI.WebControls.Button testBtn;

    override protected void OnInit(EventArgs e)
    {
    testBtn.Click += new EventHandler(testBtn_Click);
    }

    private void testBtn_Click(object sender, EventArgs e)
    {
    msgLbl.Text = "Hello World!";
    }
    }


    Best regards
    Hendrik W. Hansen
    Hendrik W. Hansen, May 28, 2004
    #1
    1. Advertising

  2. Hendrik W. Hansen

    Sam Guest

    Change it to the following:

    public class WebForm1 : System.Web.UI.Page
    > {
    > protected System.Web.UI.WebControls.Button load1Btn;
    > protected System.Web.UI.WebControls.PlaceHolder placeHolder;
    > protected System.Web.UI.WebControls.Button load2Btn;
    >
    > override protected void OnInit(EventArgs e)
    > {
    > load1Btn.Click += new EventHandler(load1Btn_Click);
    > load2Btn.Click += new EventHandler(load2Btn_Click);

    Note--> EnsureChildControls();
    > }
    >
    > protected override void CreateChildControls()
    > {
    > placeHolder.Controls.Clear();

    placeHolder.Controls.Add(LoadControl("DynamicControl1.ascx"));
    placeHolder.Controls.Add(LoadControl("DynamicControl2.ascx"));
    placeHolder.Controls[0].Visible = false;
    placeHolder.Controls[1].Visible = false;
    > base.CreateChildControls();
    > }
    >
    > private void load1Btn_Click(object sender, EventArgs e)
    > {
    > placeHolder.Controls[0].Visible = true;

    placeHolder.Controls[1].Visible = false;
    > }
    >
    > private void load2Btn_Click(object sender, EventArgs e)
    > {
    > placeHolder.Controls[0].Visible = false;

    placeHolder.Controls[1].Visible = true;
    >
    > }
    > }


    Explanation: (btw, the above scheme is somewhat inefficient)

    You are switching the user controls at button click. The new user
    control won't receive the button click because the Page RaisePostBack
    event has already been fired (thats how you got to the first button
    click handler in the first place). This is an event that does not
    play 'catch up' for loaded user controls (although Init, OnLoad,
    OnPreRender, and a few others do). Your code only works when your
    page load just happens to load the same control as you add in the
    button click. See http://aspalliance.com/articleViewer.aspx?aId=134&pId=
    for details.

    BTW, CreateChildControls is only called when you call
    EnsureChildControls (although the framework will call it for you in a
    few places). So its not a lifecycle event like the others.

    You can load the proper user control on Init if you want to, but that
    means either changing a hidden field through javascript in the onclick
    handlers of your buttons, and then checking for that field in Init, or
    checking Page.Request.Form["__EVENT_TARGET"] for the UniqueID of the
    button you clicked. BTW, you are not assigning IDs explicitly when
    you add the user controls. You should really do that and use
    FindControl instead of indexing them by number like I did above.

    If this doesn't solve everything then please ask again.

    -Sam
    Sam, May 30, 2004
    #2
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Hendrik W. Hansen

    Loading UserControls dynamically

    Hendrik W. Hansen, Oct 28, 2003, in forum: ASP .Net
    Replies:
    0
    Views:
    412
    Hendrik W. Hansen
    Oct 28, 2003
  2. Sundaresan
    Replies:
    1
    Views:
    319
    Natty Gur
    Nov 23, 2003
  3. Brett
    Replies:
    1
    Views:
    471
    Brett
    Sep 9, 2004
  4. =?Utf-8?B?QWxhbiBMYW1iZXJ0?=

    Dynamically adding usercontrols

    =?Utf-8?B?QWxhbiBMYW1iZXJ0?=, Sep 26, 2004, in forum: ASP .Net
    Replies:
    1
    Views:
    413
  5. Darrel
    Replies:
    3
    Views:
    3,921
    Darrel
    Nov 8, 2004
Loading...

Share This Page