以下所有名称都是通用的,而不是实际使用的名称。
我有一个自定义的UserControl,其Panel包含一些标签,两个.aspx控件。
的.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>
代码隐藏:
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;
}
在另一个页面上,在后面的代码中,我创建了一个自定义用户控件的新实例。
protected void Page_Load(object sender, EventArgs e)
{
Usercontrol control = new UserControl(object);
Controls.Add(control);
}
用户控件接受参数并尝试根据传入的对象设置标签。
但是,它尝试将值分配给的标签为null。
这是一个我不理解的ASP.net生命周期问题吗?我基于Microsoft ASP.net lifecycle page的理解是页面控件在Page_Initialization之后可用。
这样做的正确方法是什么?还有更好的方法吗?
编辑:从下面我尝试过使用Page.LoadControl。
如果我根据路径和文件名的字符串表示加载控件,则禁止传递参数。我可以通过添加允许我设置对象的方法来避免这种情况。这虽然有效,但感觉很乱。如果可能的话,我希望能够将值传递给构造函数。
使用重载方法会产生与仅加载后面的代码相同的结果,正在分配的标签为空。
编辑:显然,重载方法没有实例化.ascx文件中添加的子控件是“按设计”。我在Microsoft's page for Page.LoadControl(type, object[])
的评论中找到了这个答案 0 :(得分:11)
当您在用户控件的类后面创建代码实例时,不会创建用户控件的实例。实际的用户控件是从.ascx文件中的标记创建的类,该类继承自类后面的代码。
如果要动态创建用户控件,请使用Page.LoadControl
方法。它将创建一个用户控件的实例,其中控件引用后面的代码对应于从标记创建的控件:
CustomControl control = (CustomControl)Page.LoadControl("controls/CustomControl.ascx");
但是这并没有让你有机会将参数发送给构造函数,所以你可能想要使用带有类型的重载:
CustomControl control = (CustomControl)Page.LoadControl(typeof(CustomControl), new object[] { objectToDisplay } );
(我不确定类型参数应该是什么。逻辑上它应该是.ascx页面的类型而不是类后面的代码类型。)
答案 1 :(得分:10)
在页面/父用户控件的标记中使用Register指令:
<%@ Register TagPrefix="wb" src="~/CustomControl.ascx" TagName="CustomControl" %>
<asp:CustomControl runat="server" />
答案 2 :(得分:0)
您可以尝试在自定义控件的Page_Load处理程序中调用EnsureChildControls,尽管AFAIK不是绝对必要的。
何时/何处将自定义控件添加到Controls集合?