0

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

我遇到了在不同的 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 属性的基于代码的切换;还是没有骰子!

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

4

2 回答 2

2

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

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

于 2009-08-25T02:27:55.407 回答
1

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

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

HTH,安德森

于 2009-08-25T06:20:10.837 回答