Постраничный вывод результатов запроса
Задача.
Как я раньше уже упоминал, стояла следующая задача:
1. Постраничный вывод результатов запроса
2. Не в DataGrid (ибо запись нужно выводить в несколько строк)
Первая попытка.
Вроде как ничего сложного, да? :) Вот и я так думал. И пошел прямым путем:
1. Положил PlaceHolder на страницу
2. В уже ставшем стандартом де факто методе bindData на этот PlaceHolder набросал нужное количество LinkButton и добавил один на всех обработчик.
Как оно было.
Откомпилил, запустил... Класс, все показывается, к-во страниц выводится красиво и правильно. Жму на LinkButton чтобы перейти на другую страницу и... фиг. В смысле страница перегружается, данные выводятся те же, PlaceHolder пустой! Вообщем обработчик нажатия на LinkButton и не думал стартовать...
И тогда я начал заниматься шаманством :) Вначале была попытка добавить хранилище кнопок в виде приватного массива - не прошло. Потом я решил попробовать вставить код отображения кнопок в Page_Load (просто фиксированного размера, ибо на тот момент неизвестно же еще ни количества страниц, ни текущей страницы). Заработало! Еще парочка экспериментов привела меня к мысли, что для того, чтобы обрабатывалось событие какого-либо элиемента, необходимо, чтобы этот элемент был создан до завершения работы Page_Load!
Ладно, подумалось, многого в этой жизни можно достичь не единственным путем. И пошел я делать сервер контрол аналогичный. В смысле в сервер контрол передается к-во страниц и номер текущей страницы и в зависимости от этих параметров добавляются конпки. Ну и евент срабатывает, мол навигатиться пора. Код не привожу ибо убил потом :)
Как возможно вам уже стало понятно этот метод тоже не прокатил :) Причем примерно точно так же, как и прошлый - первый раз все выводится на ура, затем евенты по нажатию не обрабатываются.
"Шок - это по нашему" (из рекламы русского национального продукта). Поиски по всем известным сайтам решения данной проблемы (запуск евентов для контролов, добавляемых программно не в Page_Load) результатов не дали. Чтение Professional ASP.NET тоже вначале ничего не дало. И только на 3-й день мучений и проб я наткнулся на решение моей задачки.
Вообщем краткий солюшн. В System.Web.UI есть интерфейс IPostBackEventHandler с методом RaisePostBackEvent, позволяющим обрабатывать событие посылки формы через скрипт, сгенерированный методом Page.GetPostBackEventReference. Вообщем за более подробным описание - в доку и в Professional ASP.NET (глава 18, стр 916-919) :). А рез-т (в смысле server control) представляю:
Sources AKA solutionusing System;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace Dimon.Web.Controls
{
/// <summary>
/// Summary description for navPanel.
/// </summary>
///
public delegate void NavEventHandler(Object sender, NavEventArgs e);
public class navPanel_ctrl : System.Web.UI.WebControls.WebControl, IPostBackEventHandler
{
private int numPages;
private int currPage;
public event NavEventHandler Navigate;
public int PagesTotal
{
get
{
return numPages;
}
set
{
numPages = value;
}
}
public int PageCurrent
{
get
{
return currPage;
}
set
{
currPage = value;
}
}
public navPanel_ctrl()
{
numPages = 0;
currPage = 0;
}
protected override void Render(HtmlTextWriter writer)
{
int[,] pageRanges = new int[3, 2]
{
{1, 3},
{currPage - 2, currPage + 2},
{numPages - 2, numPages}
};
if (pageRanges[0, 1] + 1 >= pageRanges[1, 0])
{
if(pageRanges[0, 1] < pageRanges[1, 1])
pageRanges[0, 1] = pageRanges[1, 1];
pageRanges[1, 0] = -1000;
}
if((pageRanges[1, 0] != pageRanges[1, 1]) && (pageRanges[1,1] + 1 >= pageRanges[2,0]))
{
if (pageRanges[2, 0] > pageRanges[1, 0])
pageRanges[2, 0] = pageRanges[1, 0];
pageRanges[1, 0] = -1000;
}
if (pageRanges[0, 1] + 1 >= pageRanges[2, 0])
{
pageRanges[0, 1] = pageRanges[2, 1];
pageRanges[2, 0] = -1000;
}
for(int rangeIndex = 0; rangeIndex <= 2; rangeIndex++)
{
if(pageRanges[rangeIndex, 0] != -1000)
{
if(rangeIndex != 0)
writer.Write (" . . . ");
int pgIndex = pageRanges[rangeIndex, 0];
do
{
if(pgIndex == currPage)
writer.Write(String.Format("<b>{0}</b> ", pgIndex.ToString()));
else
writer.Write("<a href=\"javascript:" +
Page.GetPostBackEventReference(this, pgIndex.ToString()) +
"\">" + pgIndex.ToString() + "</a> ");
pgIndex++;
}
while (pgIndex <= pageRanges[rangeIndex,1]);
}
}
}
public void RaisePostBackEvent(string arg)
{
int cmd = Int32.Parse(arg);
NavEventArgs e = new NavEventArgs();
e.SelectedPage = cmd;
OnNavigate(e);
}
protected virtual void OnNavigate(NavEventArgs e)
{
if (Navigate != null)
Navigate(this, e);
}
}
public class NavEventArgs : EventArgs
{
public int SelectedPage;
}
}
Почти Summary.
Таким образом я избежал проблемы добавления контролов с обработчиками. И заодно реализовал "красивое" отображение номеров страниц при их (страниц) большом количестве