Loading Dynamic User Controls - Resoluton

by Erik Lane 11. February 2005 07:25

The issue I posted last night was eating at me.  I knew I was missing something since it would work if I added the controls at design time, so I kept reading and searching and trying different things.  If I would've just been patient good guys like David would've led me in correct direction.  Thanks David!

Well, I found another of Scott Mitchell's articles - Dynamic Web Controls, PostBacks, and ViewState.  When I scan technical articles I usually read the title, read a few lines of the intro, and then start scrolling using handy-dandy wheel on my mouse.  Side note:  Jeff's post yesterday on keyboards specific to developers is pretty interesting and I plan to comment on it later.

As I was scrolling at a 100mph I saw this headline "Adding Controls at the Right Time".  I stopped and began to really read.  His first sentence was "We already know that when adding controls dynamically through the page's code portion the controls must be added on every postback." (and this is what David pointed out too).  I'm guessing he's not including me in his "we" so I continued reading so I could now include myself in this cool club.

So now I know that dynamic controls must be added prior to the LoadViewState stage of the ASP.NET Page Lifecycle.  To do this I took the advice and created a simple method in my code-behind and call it from the page's OnInit event handler.  A few tweaks and now it works like a champ.


override protected void OnInit(EventArgs e)
{
	InitializeComponent();
	base.OnInit(e);
	CustomOnInit();
}
private void CustomOnInit()
{
	string ID = string.Empty;
	PostDataControl pdc = new PostDataControl();
	try
	{
		ID = Request.QueryString["id"];
		if(ID == null || ID == string.Empty)
			ID = "01";
		string controlName = ID + ".ascx";
		pdc = (PostDataControl)LoadControl(controlName);
	}
	catch(System.IO.FileNotFoundException)
	{
		// Catch bogus querystings and load a default screen.
		ID = "01";
		string controlName = ID + ".ascx";
		pdc = (PostDataControl)LoadControl(controlName);
	}
	finally
	{
		pdc.ID = "pdc";
		pdc.Code = ID;
		FormPlaceHolder.Controls.Add(pdc);
	}
}
Tags:

Comments

David Neal
David Neal on 2/11/2005 1:49:00 AM

Ahhh... good stuff, ain't it? ;)

eriklane
eriklane United States on 2/11/2005 1:55:00 AM

Sure is.  Thanks again!

mike
mike on 2/11/2005 5:06:00 AM

Maybe I'm missing something, but I don't think this will work if the querystring is bad.
The first line in the try block will throw an error and execution will jump to the catch block. However, the catch block is looking for an exception of type "System.IO.FileNotFoundException." A missing querystring throws an exception of "Object Reference not set to an Instance of an Object." So the error will have been "handled" as far as the framework is consernd, but the problem will not be addressed. So won't the code then move to the finally block and try to assign an empty string to the pdc.Code property?

You can try this for yourself:

    private void Page_Load(object sender, System.EventArgs e)
    {
      try
      {
        string x = Request.QueryString["x"].ToString();
        if(x == null || x == string.Empty)
          Response.Write("error");
        Response.Write(x);
      }
      catch(System.IO.FileNotFoundException ex)
      {
        Response.Write(ex.Message);
      }
      catch(Exception ex)
      {
        Response.Write(ex.Message);
      }
    }

eriklane
eriklane United States on 2/11/2005 9:32:00 AM

Mike,

Thanks for the feedback.  The example you posted is a little different from what I'm doing and mine doesn't throw the NullReference Exception.  I'm trying to catch a FileNotFoundException because I'm trying to load a user control and if it doesn't exist that's the exception that is thrown.

The exception you are getting is due to this line of code in your example:
"string x = Request.QueryString["x"].ToString(); "

If, in the QueryString collection, "x" doesn't exist you can't call its ToString() method and you get the ObjectReference exception.  That's why I'm checking for that after I try and retrieve the value and before I try and load a user control based on that value.

Thanks again for the feedback.

Ruslan
Ruslan on 6/23/2005 7:30:00 AM

hey Erik thanx for  your  writing. I love it.
my question  what if I  am adding  more than one usercontrol at runtime. there is a
button , whenever you press you should add a new usercontrol. It s alittle get hard
to handle with ID. coz I also have a Remove button on each added user control. Can
you give me some ideas?

thanx in advance

eriklane
eriklane United States on 6/23/2005 7:45:00 AM

Ruslan,

Sorry, I accidentaly deleted your post yesterday.  I had to restore from a backup that was from before your post.  Luckily I still had the e-mail and  I reposted it just now.

Back to you question...
The ID I'm using in my example here is a custom ID that made up and know beforehand.  It actually represents the user control's name.

In  your scenario,  I think you could generate a random IDs and then store them in a collection...then store that as a session variable.  Each time a new user control is created add it to that collection and update your session variable.  This will help you know which ones you have on the page and how many.

When a delete button is clicked on a user control, assuming you are wanting to remove another user control, you can pass in the ID of the control you want to remove.  Remove its ID from the session variable just after you remove it from the page.

Hope this helps some.

Comments are closed