15

我在使用时遇到问题LoadControl( type, Params )。让我解释...

我有一个超级简单的用户控件(ascx)

<%@ Control Language="C#" AutoEventWireup="True" Inherits="ErrorDisplay" Codebehind="ErrorDisplay.ascx.cs" EnableViewState="false" %>

<asp:Label runat="server" ID="lblTitle" />
<asp:Label runat="server" ID="lblDescription" />

后面有代码( c# ):

public partial class ErrorDisplay : System.Web.UI.UserControl
{

    private Message _ErrorMessage;    

    public ErrorDisplay()
    {
    }

    public ErrorDisplay(Message ErrorMessage)
    {
        _ErrorMessage = ErrorMessage;
    }    

    protected override void OnPreRender(EventArgs e)
    {
        base.OnPreRender(e);

        if (_ErrorMessage != null)
        {
            lblTitle.Text = _ErrorMessage.Message;
            lblDescription.Text = _ErrorMessage.Description;
        }
    }
}

在我的 Web 应用程序的其他地方,我使用以下代码将用户控件的实例添加到页面:

divValidationIssues.Controls.Add(LoadControl(typeof(ErrorDisplay), new object[] { MessageDetails }));   

我正在使用 LoadControl 的重载版本,因为我想将 Message 参数传递给构造函数。这一切似乎工作正常。

但是,当在OnPreRender()ErrorDisplay 用户控件上触发时, lblTitle 和 lblDescription 变量都是null,尽管它们具有等效的标记。消息变量已正确填充。

谁能解释为什么会发生这种情况?

谢谢

编辑:

为清楚起见,我还将添加以编程方式将用户控件添加到页面的代码正在运行以响应按钮按下,因此“托管页面”已通过 Init、Page_Load 进行,现在正在处理事件处理程序。

我无法在早期的 asp 生命周期阶段添加用户控件,因为它们是为响应按钮单击事件而创建的。

4

6 回答 6

23

我也尝试过以下代码 - 产生相同的结果(即 lblTitle 和 lblDescription 均为空)

protected void Page_Load(object sender, EventArgs e)
{
    if (_ErrorMessage != null)
    {
        lblTitle.Text = _ErrorMessage.Message;
        lblDescription.Text = _ErrorMessage.Description;
    }
}

我的理解是 LoadControl 函数将它正在加载的控件带到包含它的页面的当前“状态”。因此 Init、Page_Load 等都作为 LoadControl 调用的一部分运行。

有趣的是,这个(未回答的)asp.net 论坛帖子与我遇到的问题相同。

MSDN 论坛帖子

另外——来自 MSDN:

当您将控件加载到容器控件中时,容器会引发所有添加的控件的事件,直到它赶上当前事件为止。但是,添加的控件无法赶上回发数据处理。要使添加的控件参与回发数据处理(包括验证),必须将控件添加到 Init 事件而不是 Load 事件中。

因此 LoadControl 不应该正确初始化控件吗?

编辑:

好的,所以我在这里回答我自己的问题..

我找到了我在上面链接到的论坛帖子的回答版本这里

本质上,答案是LoadControl( type, params )无法推断要解析的“page infront” ascx,因此它不会打扰初始化任何控件。当您使用该LoadControl( "ascx path" )版本时,它会在前面给出页面,因此会进行所有解析和初始化。

所以总而言之,我需要更改初始化控件的代码并将其拆分为单独的部分。IE

Control ErrorCntrl = LoadControl("ErrorDisplay.ascx");
ErrorCntrl.ID = SomeID;
(ErrorCntrl as ErrorDisplay).SetErrorMessage = MessageDetail;
divErrorContainer.Controls.Add(ErrorCntrl);

它应该可以正常工作。它不像我之前的尝试那样整洁,但至少它会起作用。

我仍然愿意接受改进上述内容的建议。

干杯

于 2008-10-27T18:41:45.787 回答
0

同意 Mitchel 的观点,您应该能够在控件代码本身中放置一个 page_load,它会在控件完全可用后触发。

于 2008-10-27T18:17:18.283 回答
0

好吧,在您运行构造函数并将控件添加到页面后,总会添加您自己的加载事件并调用它,但它与您所拥有的并没有太大不同,尽管我可能出于风格原因选择它。

很高兴您找到了问题的答案!

于 2008-10-27T21:49:41.587 回答
0

是 Steven Robbins 写的博客文章。该帖子解释了如何使用 为用户控件传递参数LoadControl,类似于将LoadControl(Type, object[])要执行的操作,但它可以工作:)

于 2013-11-26T14:46:25.973 回答
0

我对日历控件 DayRender 事件有类似的问题,因为我想将用户控件添加到 e.Cell.Controls 集合。在尝试了几种失败的方法后,用户控件 page_load 未触发或 ascx 上的列表框抛出空异常,我发现如果我使用 LoadControl(ascx) 初始化表单上的控件,然后开始访问标记控件上ascx,一切正常。这种方法根本不依赖于 ascx 上的 Page_Load 事件。

ASCX 标记

后面的代码

公共类 CPCalendarCell 继承 System.Web.UI.UserControl

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

End Sub

Public Sub Add(txt As String)
    Dim li As New ListItem(txt, txt)
    lstDay.Items.Add(li)
End Sub

结束类

页面 ASPX 标记

表单上的日历 DayRender 事件背后的代码

Private Sub Calendar1_DayRender(sender As Object, e As System.Web.UI.WebControls.DayRenderEventArgs) Handles Calendar1.DayRender
    Dim div As CPCalendarCell = LoadControl("~/UserControls/CPCalendarCell.ascx")
    div.ID = "dv_" & e.Day.Date.ToShortDateString.Replace(" ", "_")

    **e.Cell.Controls.Add(div)**

    div.Add(e.Day.Date.Month.ToString & "/" & e.Day.Date.Day.ToString)
    div.Add("Item 1")
    div.Add("Item 2")
    e.Cell.Style.Add("background-color", IIf(e.Day.IsWeekend, "whitesmoke", "white").ToString)
End Sub
于 2014-04-20T15:29:01.397 回答
-1

根据 asp.net 页面生命周期,您的控件没有完全添加到预渲染中,为什么不直接加载 page_load 中的值?

于 2008-10-27T18:02:03.433 回答