Sunday, April 17, 2011

Failing to add controls to a page dynamically

I'm adding a User Control for each record pulled up in a data reader, here's the basic loop:

while (dr.Read())
{
     ImageSelect imgSel = new ImageSelect(dr["Name"].ToString());
     myPanel.Controls.Add(imgSel);
}

The problem is that there are no controls added to the page, I check the html output and there is my panel, with nothing in it.

I even stepped through the code in the debugger, and verified that myPanel.Controls gets a control added on each loop, with the count being 6, no errors, but then they dont show up on the page.

I've run the above code in the Page_Init and Page_Load events, both with the same result.

EDIT: Ok so I've switched to using LoadControl("....ascx") to get my control instance, which is now working. But originally I was also passing in data via the controls constructor.. Is this still possible or do I just need to set them via get/sets?

EDIT 2: Thanks to Freddy for pointing out that the LoadControl has an overload where you CAN pass in constructor params, see accepted answer.

EDIT 3: After trying this method both with and without the constructor. I have found its better to just use setters for any properties I want the control to have versus trying to use the passed in object array for my constructor.

From stackoverflow
  • Update: As Steve pointed out, the overload of LoadControl that uses the type won't take into account the controls in the ascx. This is also mentioned in this answer: http://stackoverflow.com/questions/450431/dynamically-loading-a-usercontrol-with-loadcontrol-method-type-object/450449#450449.

    As I mentioned before, the get/set are more in line with the asp.net model, so I recommend using that with the LoadControl variation that receives the user control path. That said, the Steve's version is an interesting alternative: http://www.grumpydev.com/2009/01/05/passing-parameters-using-loadcontrol/.

    My take is the LoadControl with type is meant to be used with web custom controls instead.


    If it is an user control you should use LoadControl(usercontrolpath) to get the instance of the user control.

    You can use a constructor by doing:

    var name = dr["Name"].ToString();
    var imgSel = LoadControl(typeof(ImageSelect), new object[]{ name });
    myPanel.Controls.Add(imgSel);
    

    Notice that depending on the project model you are using, you need to add a Reference to the aspx to use it with the typeof variation:

    <%@ Reference Control="~/somepath/myusercontrol.ascx" %>
    

    Ps. I usually use the set/get for controls as I find them more in line with the asp.net model

    Neil N : can you expand on that? .Load of what? The page?
    eglasius : @Neil y, updated it, memory failed, it is LoadControl and you specify the path to the user control, as in: "~/somepath/mycontrol.ascx"
    Neil N : ok, got it, now can I use constructor parameters LoadControl, like I did in my original example?
    eglasius : y, posted an update for that too :)
    Neil N : ok, great, missed that overload of LoadControl in intellisense. Thanks for the explanations.
    Steven Robbins : Bear in mind that that overload doesn't work the same way as the other one, so you may get null reference exceptions if you have designer items in there. There's an extention method on my blog to work around it if needed.
    eglasius : @Steve thx, updated it. That's a nice trick btw.
    Steven Robbins : No worries, as you said, the other overload is more for custom WebControls, so it's slightly confusing having them both with the same name.
  • To add UserControls you must call the LoadControl method passing in the path to the .ascx file. You can not create them by just instantiating the object the .ascx file inherits from.

    A UserControl consists of both the markup and the class in the code behind. The markup contains a link to the class behind, but the class behind does not know where the markup lives and therefore can not be created on it's own.

    Neil N : ++; thanks for the explanation, that makes sense now.

0 comments:

Post a Comment