【问题标题】:Loading of controls outside of Page_Load is a no-no?在 Page_Load 之外加载控件是不行的吗?
【发布时间】:2010-11-22 11:34:52
【问题描述】:

对于发布如此冗长的问题,我提前道歉。信不信由你,你在这里看到的实际上代表了手头问题/代码的一个相当浓缩的版本。虽然我会很感激任何关于更好或不同方法的指示,但我也非常希望了解这一点,以便我可以在晚上睡觉:)

我遇到了在不同的 aspx 页面之间传递确认消息的要求。我选择不使用查询字符串变量,因为查询字符串值“是”粘性的(即它们在所有后续回发中持续存在)并且我不想处理围绕此添加一堆条件逻辑。

无论如何,我想出了一个非常简单的类,它使用 Session 将通知与特定 URL 相关联。然后,我挂钩了我的母版页 Page_Load 事件,以查询此类以获取应为当前 URL 显示的任何通知。如果找到,它会动态加载 NotificationMessage 用户控件并显示消息内容。

尝试在不同的 aspx 页面之间传递通知时,一切都按预期工作。可以预见的是,当内容页面尝试向自身添加通知时(即“您输入的数据无效,请再试一次”),事情就不起作用了。原因很清楚:当内容页面为自己添加通知时,母版页的 Page_Load 事件已经触发,因此在页面生命周期中为时已晚,无法做任何事情。相关代码贴在下面。

    public class MyMasterPage:MasterPage{

    protected void Page_Load(object sender, EventArgs e)
    {
        LoadNotifications(this.Request.Url.ToString());
    }


    private void LoadNotifications(string url)
    {
        //look for a notification
        Notification? notification = NotificationManager.Instance.RetrieveNotification(url);

        //there are no notifications, nothing to see here 
        if (!notification.HasValue)
        {
            return;
        }

        //there is a Notification for this url, so load it into a user control
        NotificationMessage notificationMessageControl = (NotificationMessage)LoadControl("~/App_UserControls/NotificationMessage.ascx");
        notificationMessageControl.ID = "notificationMessage";
        notificationMessageControl.Notification = notification;
        notificationMessageControl.Visible = true;

        //find the placeholder on the master page
        PlaceHolder placeHolder = (PlaceHolder)PageUtils.FindControlRecursive(this, "NotificationPlaceholder");

        if (placeHolder == null)
        {
            throw new ApplicationException("NotificationPlaceholder control not found.");
        }

        //insert into control
        placeHolder.Controls.Add(notificationMessageControl);
        placeHolder.Visible = true;

        //remove the notification so it doesn't show up next time
        NotificationManager.Instance.RemoveNotification(url);


    }

}

鉴于上面提到的生命周期,我修改了 NotificationManager 类,以便在为当前页面添加通知时引发事件。母版页拦截该事件,如果 Page_Load 已经触发,它会重新启动 LoadNotifications 方法。

 //bind the event on the page constructor
    public MyMasterPage()
    {
        NotificationManager.Instance.NotificationAdded += this.NotificationAdded;

    }

    private void NotificationAdded(string forUrl)
    {
        if (_pageLoaded){
           LoadNotifications(forUrl);
        }
    }

很遗憾,这不起作用。我已多次单步执行此代码,尽管母版页加载 NotificationMessage UserControl 并将其添加到适当的占位符中,但最终的 aspx HTML 从不 包含该 UserControl 的标记。我在 UserControl 的 Page_Load 中放置了断点,并验证它们确实在执行过程中被击中。

如果我从内容页面内部动态加载 UserControl 并完全绕过母版页面,它会顺利呈现:

public partial class MyContentPage:Page
{

    public void DoSomethingCool(object sender, EventArgs e)
    {
        if (MyServiceLayer.Save(foo)==false){
            Notification notification = new Notification(NotificationType.Error, "We’re sorry, your document was not saved.");
            NotificationMessage notificationMessage = (NotificationMessage)LoadControl("~/App_UserControls/NotificationMessage.ascx");
            notificationMessage.Notification = notification;
            notificationMessage.Visible = true;
            PlaceHolder holder = (PlaceHolder)PageUtils.FindControlRecursive(this, "NotificationPlaceholder");
            holder.Controls.Add(notificationMessage);
        }
    }
}

作为记录,我去掉了 UserControl 的动态加载,而是选择了母版页标记中的静态声明和控件的 Visible 属性的基于代码的切换;还是没有骰子!

如果有人能阐明这个难题,我将不胜感激。

【问题讨论】:

    标签: asp.net dynamic controls render lifecycle


    【解决方案1】:

    我以前尝试过这种事情,但我从来没有完全适应过它。相反,我所做的是将我的 ASCX 放在每个页面(或母版页)上,让 ASCX 控制其状态,而不是让 ASPX 控制我的 ASCX。

    不过,我不确定这是否会对您的情况有所帮助。

    【讨论】:

    • 听起来很有趣。能否举例说明一下?
    【解决方案2】:

    您似乎希望在控制事件触发后显示您的信息。您可能会考虑让这些消息聚合,直到所有控制事件都被触发,然后从OnPreRender 中的NotificationManager 中提取所有消息,而不是Page_Load。这样您就可以摆脱可能使事情复杂化的事件(如NotificationAdded)等。

    不过,问题不是 100%。有时了解 MasterPage 实际上是 Page 上的一个控件,而不是像您想的那样反过来会有所帮助。它将受到页面上任何控件的限制。

    HTH,安德森

    【讨论】:

      猜你喜欢
      • 2013-02-26
      • 2015-01-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多