Недавно возникла задача – загружать часть контента после загрузки страницы, т.к. получение и обработка данных в этой части страницы происходит чуть дольше, чем обработка данных остальной части страницы.
Решено было поставить просто OutputCache, но он был убран, скорее всего ввиду того, что данные обновлялись несколько чаще, чем происходило обновление кэша, потому, когда я преступил к работе – его уже не было. Кэшировались только запросы, хотя тоже не особо помогло.
Собственно – была поставлена задача сделать отложенную загрузку части страницы, и как – не важно, лишь бы ajax, догружающий на window.onload страницы ее часть, и решение было применимо при условии жесткой связи контролов страницы (которые следовало догружать) со страницами, настройками текущего пользователя и даже с контролами на MasterPage.
Итак, задание есть – реализовать нужно сегодня.
Первым делом решил погуглить, наткнулся на статью Гайдара Магданурова - Отложенная загрузка фрагментов страницы, но вариант подгружать контролы «вручную», не подходит для меня, т.к. необходимо сохранить его работоспособность, т.е. постбеки и связь с мастер-страницей, хотя в голове и мелькал изврат по созданию экземпляра не просто Page, а MyPage J, но это реально изврат.
Обходить через делегаты вызовы методов со страниц ну очень не хотелось, мне так посоветовали на http://inln.ru/Blog/post/Lazy-Load-Control.aspx
В итоге – был реализован расширенный UpdatePanel, позволяющий догружать часть страницы после загрузки с вызовом делегата, на обновлении панели, в котором можно размещать код, биндящий содержимое UpdatePanel.
Также этот UpdatePanel позволяет управлять порядком обновлений, т.е. можно выставить приоритеты обновления частей страницы.
Каким образом можно поставить на обновление части страницы:
<cms:DeferredUpdatePanelUpdatePriority="0" runat="server" UpdateMode="Conditional">
<ContentTemplate>
<%=DateTime.Now.Millisecond %>
</ContentTemplate>
</cms:DeferredUpdatePanel>
<cms:DeferredUpdatePanelUpdatePriority="2" runat="server" UpdateMode="Conditional">
<ContentTemplate>
<%= DateTime.Now.Millisecond %>
</ContentTemplate>
</cms:DeferredUpdatePanel>
Сначала загрузится первая панель, потом вторая, за это отвечает свойство UpdatePriority, чем оно выше – тем позденее панель обновится.
Но что делать, если нужно вывести именно данные? Тут на помощь приходит событие OnDeferredUpdated – оно вызывается, когда панель необходимо обновить, точнее – когда он сам хочет обновиться, а именно – при первой загрузке страницы.
Для теста на странице разместим даталист, выводящий нам все числа, от 1 до 200, но выводится они будут только после загрузки страницы, т.е. подгрузятся аяксом:
<cms:DeferredUpdatePanelID="defPanel" UpdatePriority="2" runat="server" UpdateMode="Conditional" OnDeferredUpdated="defPanel_OnDeferredUpdated" OnPreUpdatingJS="onPreUpdating" OnUpdatingJS="onUpdating" OnUpdatedJS="onUpdated">
<ContentTemplate>
<asp:DataList runat="server" RepeatColumns="20" ID="listNothing" Width="100%" BorderWidth="1" BorderStyle="Dotted" CellPadding="0" CellSpacing="0">
<ItemStyle Width="5%" BorderStyle="Groove" />
<ItemTemplate>
<%# Container.DataItem %>
</ItemTemplate>
</asp:DataList>
</ContentTemplate>
</cms:DeferredUpdatePanel>
Заметьте, что есть обработчик события обновления OnDeferredUpdated:
protectedvoid defPanel_OnDeferredUpdated(object sender, DeferredUpdatePanelEventArgs e)
{
List<int> list = new List<int>();
for (int i = 0; i < 100; i++)
list.Add(i);
listNothing.DataSource = list;
listNothing.DataBind();
}
Именно в нем то мы и биндим все необходимые данные. Возможно кто-то скажет – «Да это и так просто можно сделать на OnLoad+ пара скриптов», что же, он будет прав, но если таких панелей 3 на странице – то код уже становится некрасивым и на обладку у новичка уйдет от получаса до часа, так что – лучше просто иметь подобный контрол.
Какие плюсы у этого контрола:
Демонстрационный пример можно увидеть на тестовом сайте и скачать оттуда же :)
UPD:
Решено было поставить просто OutputCache, но он был убран, скорее всего ввиду того, что данные обновлялись несколько чаще, чем происходило обновление кэша, потому, когда я преступил к работе – его уже не было. Кэшировались только запросы, хотя тоже не особо помогло.
Собственно – была поставлена задача сделать отложенную загрузку части страницы, и как – не важно, лишь бы ajax, догружающий на window.onload страницы ее часть, и решение было применимо при условии жесткой связи контролов страницы (которые следовало догружать) со страницами, настройками текущего пользователя и даже с контролами на MasterPage.
Итак, задание есть – реализовать нужно сегодня.
Первым делом решил погуглить, наткнулся на статью Гайдара Магданурова - Отложенная загрузка фрагментов страницы, но вариант подгружать контролы «вручную», не подходит для меня, т.к. необходимо сохранить его работоспособность, т.е. постбеки и связь с мастер-страницей, хотя в голове и мелькал изврат по созданию экземпляра не просто Page, а MyPage J, но это реально изврат.
Обходить через делегаты вызовы методов со страниц ну очень не хотелось, мне так посоветовали на http://inln.ru/Blog/post/Lazy-Load-Control.aspx
В итоге – был реализован расширенный UpdatePanel, позволяющий догружать часть страницы после загрузки с вызовом делегата, на обновлении панели, в котором можно размещать код, биндящий содержимое UpdatePanel.
Также этот UpdatePanel позволяет управлять порядком обновлений, т.е. можно выставить приоритеты обновления частей страницы.
Каким образом можно поставить на обновление части страницы:
<cms:DeferredUpdatePanelUpdatePriority="0" runat="server" UpdateMode="Conditional">
<ContentTemplate>
<%=DateTime.Now.Millisecond %>
</ContentTemplate>
</cms:DeferredUpdatePanel>
<cms:DeferredUpdatePanelUpdatePriority="2" runat="server" UpdateMode="Conditional">
<ContentTemplate>
<%= DateTime.Now.Millisecond %>
</ContentTemplate>
</cms:DeferredUpdatePanel>
Сначала загрузится первая панель, потом вторая, за это отвечает свойство UpdatePriority, чем оно выше – тем позденее панель обновится.
Но что делать, если нужно вывести именно данные? Тут на помощь приходит событие OnDeferredUpdated – оно вызывается, когда панель необходимо обновить, точнее – когда он сам хочет обновиться, а именно – при первой загрузке страницы.
Для теста на странице разместим даталист, выводящий нам все числа, от 1 до 200, но выводится они будут только после загрузки страницы, т.е. подгрузятся аяксом:
<cms:DeferredUpdatePanelID="defPanel" UpdatePriority="2" runat="server" UpdateMode="Conditional" OnDeferredUpdated="defPanel_OnDeferredUpdated" OnPreUpdatingJS="onPreUpdating" OnUpdatingJS="onUpdating" OnUpdatedJS="onUpdated">
<ContentTemplate>
<asp:DataList runat="server" RepeatColumns="20" ID="listNothing" Width="100%" BorderWidth="1" BorderStyle="Dotted" CellPadding="0" CellSpacing="0">
<ItemStyle Width="5%" BorderStyle="Groove" />
<ItemTemplate>
<%# Container.DataItem %>
</ItemTemplate>
</asp:DataList>
</ContentTemplate>
</cms:DeferredUpdatePanel>
Заметьте, что есть обработчик события обновления OnDeferredUpdated:
protectedvoid defPanel_OnDeferredUpdated(object sender, DeferredUpdatePanelEventArgs e)
{
List<int> list = new List<int>();
for (int i = 0; i < 100; i++)
list.Add(i);
listNothing.DataSource = list;
listNothing.DataBind();
}
Именно в нем то мы и биндим все необходимые данные. Возможно кто-то скажет – «Да это и так просто можно сделать на OnLoad+ пара скриптов», что же, он будет прав, но если таких панелей 3 на странице – то код уже становится некрасивым и на обладку у новичка уйдет от получаса до часа, так что – лучше просто иметь подобный контрол.
Какие плюсы у этого контрола:
- Не нужно все делать самому
- Есть обработчик обновления – отличается от OnLoadименно тем, что для каждого UpdatePanelон свой, т.е. есть проверка на ClientID
- Есть возможность задать порядок обновления
- Вызываются JavaScriptфункции для подготовки части страницы перед обновлением, во время обновления и после обновления, при чем в эти функции передаются сами апдейтпанели (чисто для удобства, сокращает 2 строки кода для каждого из событий)
- Названия функций прописывать в свойствах: OnPreUpdatingJS, OnUpdatingJS, и OnUpdatedJS.
- Сохраняется событийная модель!
- Сохраняется связь контрола со страницей, с другими контролами или мастер-страницами
- Переделывать практический ничего не нужно, максимум – переместить код из обного места в другое и все
Интересное решение! У нас возникла та же проблема... попробуем прикрутить в своем проекте
ОтветитьУдалитьДа... а про полный page-life-cycle слышали? Это же сколько ресурсов надо потратить...
ОтветитьУдалитьконечно в курсе, но в asp.net при всех постбеках есть восстановление состояния и проходит весь жизненный цикл страницы
ОтветитьУдалитьресурсов - сожрет не много, если не биндить уже сбинденные данные
можете выложить тестовый пример? ссылка не доступна
ОтветитьУдалитьСсылка на сам контрол: https://skydrive.live.com/redir.aspx?cid=d8340e05f5504a6a&resid=D8340E05F5504A6A!367
ОтветитьУдалитьДовольно интересная статья.
ОтветитьУдалитьмогли бы вы еще раз выложить код контрола (старые ссылки не работают)
смотри UPD
ОтветитьУдалитьспасибо
ОтветитьУдалить