Загрузка элементов управления за пределами Page_Load - нет-нет? - PullRequest
0 голосов
/ 25 августа 2009

Заранее извиняюсь за размещение такого длинного вопроса. Верьте или нет, то, что вы видите здесь, на самом деле представляет собой довольно сжатую версию проблемы / кода под рукой. И хотя я был бы признателен за любые указатели на лучший или другой подход, я также очень хотел бы получить суть этого, чтобы я мог спать по ночам:)

Я столкнулся с требованием передавать сообщения подтверждения между различными страницами 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);
        }
    }

К сожалению, это не работает. Я проходил этот код много раз, и, несмотря на тот факт, что главная страница загружает UserControl NotificationMessage и добавляет его к соответствующему заполнителю без происшествий, конечный aspx HTML никогда не содержит разметки для этого UserControl. Я установил точки останова внутри Page_Load в UserControl и убедился, что они действительно попадают во время выполнения.

Если я динамически загружаю 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 элемента управления; до сих пор нет кости!

Если бы кто-то мог пролить свет на эту головоломку, я был бы очень признателен.

Ответы [ 2 ]

2 голосов
/ 25 августа 2009

Я пробовал подобные вещи раньше, и мне никогда не было полностью комфортно с этим. Вместо этого я поместил свой ASCX на каждую страницу (или на главную страницу) и позволил ASCX контролировать свое состояние, а не разрешать ASPX контролировать мой ASCX.

Я не уверен, что это поможет в вашей ситуации.

1 голос
/ 25 августа 2009

Похоже, вы хотите, чтобы ваша информация отображалась после того, как сработали ваши контрольные события. Вы можете рассмотреть возможность агрегирования этих сообщений до тех пор, пока не сработают все управляющие события, а затем извлечь все сообщения из NotificationManager в OnPreRender, а не Page_Load. Таким образом, вы можете избавиться от событий (например, NotificationAdded) и т. Д., Которые, вероятно, усложняют ситуацию.

Не 100% в чем проблема, хотя. Иногда полезно знать, что MasterPage на самом деле является элементом управления на странице, а не наоборот, как вы думаете. На него будут распространяться ограничения, которые любой элемент управления будет иметь на странице.

HTH, Андерсон

...