Dynamically loading and adding usercontrols after CreateChildControls

H

Hendrik W. Hansen

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
 
S

Sam

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
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,482
Members
44,901
Latest member
Noble71S45

Latest Threads

Top