Постраничный вывод результатов запроса

Постраничный вывод результатов запроса

Задача.

Как я раньше уже упоминал, стояла следующая задача:

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.

Таким образом я избежал проблемы добавления контролов с обработчиками. И заодно реализовал "красивое" отображение номеров страниц при их (страниц) большом количестве