views:

161

answers:

2

All of the names below are generic and not the actual names used.

I have a custom UserControl with a Panel that contains a a couple Labels, both .aspx controls.

.aspx:

<asp:Panel runat="server">
    <asp:Label ID="label1" runat="server">
    </asp:Label>
</asp:Panel>
<asp:Panel runat="server">
    <asp:Label ID="label2" runat="server">
    </asp:Label>
</asp:Panel>

Codebehind:

private readonly Object object;
protected void Page_Load(object sender, EventArgs e)
{
    // These are the lines that are failing
    // label1 and label2 are null
    label1.Text = object.Value1;
    label2.Text = object.Value2;
}
public ObjectRow(Object objectToDisplay)
{
    object = objectToDisplay;
}

On another page, in the code behind, I create a new instance of the custom user control.

protected void Page_Load(object sender, EventArgs e)
{
    Usercontrol control = new UserControl(object);
    Controls.Add(control);
}

The user control takes the parameter and attempts to set the labels based off of the object passed in.

The labels that it tries to assign the values to are however, null.

Is this an ASP.net lifecycle issue that I'm not understanding? My understanding based on the Microsoft ASP.net lifecycle page was that page controls were available after the Page_Initialization.

What is the proper way to do this? Is there a better way?

EDIT: From below I've tried using Page.LoadControl.

If I load the control based off of the string representation of the path and file name it prohibits passing a parameter. I can circumvent this by adding a method that allows me to set the object. While this works it feels hackish. I would prefer to be able to pass the value to the constructor if this is possible.

Using the overloaded method gives the same result as loading only the code behind, the labels that are being assigned are null.

EDIT: Apparently the overloaded method not instantiating the child controls added on the .ascx file is "by design". I found this in the comments at Microsoft's page for Page.LoadControl(type, object[])

A: 

You can try calling EnsureChildControls in the custom control's Page_Load handler, although AFAIK that shouldn't be strictly necessary.

When/where are you adding the custom control to the Controls collection?

technophile
+2  A: 

When you create an instance of the code behind class of the user control, you don't create an instance of the user control. The actual user control is the class that is created from the markup in the .ascx file, and that class inherits from the code behind class.

If you want to create user controls dynamically, you use the Page.LoadControl method. It will create an instance of the user control where the code behind control references correspond to controls created from the markup:

CustomControl control = (CustomControl)Page.LoadControl("controls/CustomControl.ascx");

But that doesn't give you an opportunity to send parameters to the constructor, so you might want to use the overload that takes a type:

CustomControl control = (CustomControl)Page.LoadControl(typeof(CustomControl), new object[] { objectToDisplay } );

(I'm not sure what the type parameter should really be. Logically it should be the type of the .ascx page rather than the type of the code behind class.)

Guffa
While I believe that what you've said here is correct the controls, when created using the overload still come up as null when I try to assign values to them. Any other thoughts?
mwright
@mwright: If you use the type of the code behind class, you have the same problem as when you create an instance of the class. You have to use the type of the class created from the markup file. The class name of the user control is based on the file name if there isn't a `ClassName` attribute in the `@Control` directive.
Guffa