GridView с пейджингом в стиле Digg

Aug 27
2007 07:42 (ASP.NET, Программирование) · English (18,235 views)

GridView — это отличный сильно кастомизируемый контрол ASP.NET. Сегодня я хочу показать, как создать наследник этого контрола, позволяющий добавлять пейджинг в стиле Digg в ваше приложение.

Для начала, отнаследуемся и добавим свойство UseCustomPager, которое будет определять, использовать или нет пейджинг в стиле Digg:

using System;
using System.Globalization;
using System.Reflection;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;

namespace App_Code
{
    public class GridViewWithPager : GridView
    {
        public bool UseCustomPager
        {
            get { return (bool?) ViewState["UseCustomPager"] ?? false; }
            set { ViewState["UseCustomPager"] = value; }
        }
    }
}

GridView содержит виртуальный метод InitializePager, который можно перегрузить для создания собственного пейджера:

protected override void InitializePager(GridViewRow row, int columnSpan, PagedDataSource pagedDataSource)
{
    if (UseCustomPager)
        CreateCustomPager(row, columnSpan, pagedDataSource);
    else
        base.InitializePager(row, columnSpan, pagedDataSource);
}

Теперь создадим собственный пейджер:

protected virtual void CreateCustomPager(GridViewRow row, int columnSpan, PagedDataSource pagedDataSource)
{
    int pageCount = pagedDataSource.PageCount;
    int pageIndex = pagedDataSource.CurrentPageIndex + 1;
    int pageButtonCount = PagerSettings.PageButtonCount;

    TableCell cell = new TableCell();
    row.Cells.Add(cell);
    if (columnSpan > 1) cell.ColumnSpan = columnSpan;

    if (pageCount > 1)
    {
        HtmlGenericControl pager = new HtmlGenericControl("div");
        pager.Attributes["class"] = "pagination";
        cell.Controls.Add(pager);

        int min = pageIndex - pageButtonCount;
        int max = pageIndex + pageButtonCount;

        if (max > pageCount)
            min -= max - pageCount;
        else if (min < 1)
            max += 1 - min;

        // Create "previous" button
        Control page = pageIndex > 1
                        ? BuildLinkButton(pageIndex - 2, PagerSettings.PreviousPageText, "Page", "Prev")
                        : BuildSpan(PagerSettings.PreviousPageText, "disabled");
        pager.Controls.Add(page);

        // Create page buttons
        bool needDiv = false;
        for (int i = 1; i <= pageCount; i++)
        {
            if (i <= 2 || i > pageCount - 2 || (min <= i && i <= max))
            {
                string text = i.ToString(NumberFormatInfo.InvariantInfo);
                page = i == pageIndex
                        ? BuildSpan(text, "current")
                        : BuildLinkButton(i - 1, text, "Page", text);
                pager.Controls.Add(page);
                needDiv = true;
            }
            else if (needDiv)
            {
                page = BuildSpan("&hellip;", null);
                pager.Controls.Add(page);
                needDiv = false;
            }
        }

        // Create "next" button
        page = pageIndex < pageCount
                ? BuildLinkButton(pageIndex, PagerSettings.NextPageText, "Page", "Next")
                : BuildSpan(PagerSettings.NextPageText, "disabled");
        pager.Controls.Add(page);
    }
}

private Control BuildLinkButton(int pageIndex, string text, string commandName, string commandArgument)
{
    PagerLinkButton link = new PagerLinkButton(this);
    link.Text = text;
    link.EnableCallback(ParentBuildCallbackArgument(pageIndex));
    link.CommandName = commandName;
    link.CommandArgument = commandArgument;
    return link;
}

private Control BuildSpan(string text, string cssClass)
{
    HtmlGenericControl span = new HtmlGenericControl("span");
    if (!String.IsNullOrEmpty(cssClass)) span.Attributes["class"] = cssClass;
    span.InnerHtml = text;
    return span;
}

Несколько настроек пейджера используются в этом коде:

  • PagerSettings.PreviousPageText — текст, который будет отображаться на кнопке “Previous”.
  • PagerSettings.NextPageText — текст, который будет отображаться на кнопке “Next”.
  • PagerSettings.PageButtonCount — сколько страниц показывать до и после текущей.

Вы могли обратить внимание, что в методе BuildLinkButton используется контрол PagerLinkButton. Это всего лишь наследник LinkButton, который упрощает использование внутри GridViewWithPager:

using System;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace App_Code
{
    public class PagerLinkButton : LinkButton
    {
        public PagerLinkButton(IPostBackContainer container)
        {
            _container = container;
        }

        public void EnableCallback(string argument)
        {
            _enableCallback = true;
            _callbackArgument = argument;
        }

        public override bool CausesValidation
        {
            get { return false; }
            set { throw new ApplicationException("Cannot set validation on pager buttons"); }
        }

        protected override void Render(HtmlTextWriter writer)
        {
            SetCallbackProperties();
            base.Render(writer);
        }

        private void SetCallbackProperties()
        {
            if (_enableCallback)
            {
                ICallbackContainer container = _container as ICallbackContainer;
                if (container != null)
                {
                    string callbackScript = container.GetCallbackScript(this, _callbackArgument);
                    if (!string.IsNullOrEmpty(callbackScript)) OnClientClick = callbackScript;
                }
            }
        }

        #region Private fields

        private readonly IPostBackContainer _container;
        private bool _enableCallback;
        private string _callbackArgument;

        #endregion
    }
}

Наш контрол почти закончен. Осталось определить метод ParentBuildCallbackArgument. Как можно увидеть из исходников GridView, этот метод используется для сериализации индекса страницы, порядка сортировки и выражения сортировки, но, по каким-то причинам, он был объявлен как внутренний (internal). Я не люблю хаки, но в этом случае считаю, что можно немного схитрить:

private string ParentBuildCallbackArgument(int pageIndex)
{
    MethodInfo m =
        typeof (GridView).GetMethod("BuildCallbackArgument", BindingFlags.NonPublic | BindingFlags.Instance, null,
                                    new Type[] {typeof (int)}, null);
    return (string) m.Invoke(this, new object[] {pageIndex});
}

Кстати, как можно заметить, я не добавлял комментарии к методам. Это сделано специально, потому что я не хочу создавать библиотеку контролов, а просто делюсь своим опытом :-)

И теперь пример использования:

<asp:XmlDataSource runat="server" ID="xdsCountries"
    DataFile="~/App_Data/CountryCodeList.xml" />


<ac:GridViewWithPager runat="server" UseCustomPager="true" AllowPaging="true"
    DataSourceID="xdsCountries" PageSize="10" AutoGenerateColumns="false">

    <PagerSettings PreviousPageText="&laquo; previous"
        NextPageText="next &raquo;" PageButtonCount="3" />

    <Columns>
        <asp:TemplateField HeaderText="Code">
            <ItemTemplate><%# XPath("CountryCoded") %></ItemTemplate>
        </asp:TemplateField>
        <asp:TemplateField HeaderText="Name">
            <ItemTemplate><%# XPath("CountryName") %></ItemTemplate>
        </asp:TemplateField>
    </Columns>
</ac:GridViewWithPager>

И скриншот:

Пейджинг в стиле Digg

Исходный код можно загрузить отсюда.

12 отзывов на 'GridView с пейджингом в стиле Digg'

Подписаться на комментарии по RSS или TrackBack на 'GridView с пейджингом в стиле Digg'.

1
Kigorw
сказал 29.08.2007 в 11.57

GridView — это отличный сильно кастомизируемый контрол ASP.NET. - Ты серьезно так считаешь?

2
сказал 29.08.2007 в 12.27

Да, и не думаю, что я сильно ошибаюсь :-) Все, что нужно - легко получить. Включая DIV’ную разметку вместо табличной, которую он генерит по умолчанию, всевозможные сортировки и пейджинги, управление блоками данных (колонками в частности). Да, это действительно отлично кастомизируемый контрол. Если есть пример того, что сложно сделать — велкам.

3
Kigorw
сказал 29.08.2007 в 13.40

Вполне допускаю что я его криво использую.

1. Была задача реализовать фильтры, встроенные в каждую колонку. Реализовал, но криво, джаваскриптом создаю строку пустую и туда засовываю фильтры.

2. Проблема в датабиндинге. Связал с обжект датасоурсом. При любом действии (то же нажатие на кнопку пейджинга) вызывается много раз DataBind, что ведет к ненужным запросом данных…

Мысль в том что не вижу смысла бороться с этой всей кастомизацией, делая элементарные действия. Не хочу думать про весь этот цикл событий жизни, вспоминая что исполнится первыми и где тут еще поставить очередной DataBind, чтоб все отрисовалось правильно…

4
Total Beaver
сказал 19.09.2007 в 22.46

Standard GridView is sux with such paging style or another.

5
сказал 19.09.2007 в 23.23

2 Total Beaver: Any arguments?

6
сказал 26.09.2007 в 16.52

Very nice one I implemented it in one of my projects and looks + works perfectly fine.

Thanks a bunch

7
сказал 26.09.2007 в 23.31

great code but does someone has the VB.net translation of this, im not into C#

thx
Wouter

8
Mel User
сказал 29.04.2008 в 9.48

All the functionalities works except when I tries to get the First and Last page index, it always return 0. Any idea why?

9
Andrew
сказал 11.08.2008 в 20.32

Hi!

Thanks for a great control. I am having a problem capturing the postback on the page click event for some reason.

I am running this with VS 2008 and ASP.NET 3.5. Could that be the problem?

Any help would be greatly appreciated.

Cheers

10
сказал 19.08.2008 в 19.22

Hey Wouter, you can use the following website to convert the code to vb.net. That’s What i did and it works perfectly

http://labs.developerfusion.co.uk/convert/csharp-to-vb.aspx

11
krishna
сказал 04.09.2008 в 12.36

All the functionalities works except when I tries to get the First and Last page index, it always return 0. Any idea why?

12
steve martin
сказал 29.09.2008 в 17.11

Thanks for sharing your work. This saves me a whole lot of time to get something that looks really good.

Оставить отзыв

Вы можете использовать простые теги форматирования HTML (вроде <a>, <ul> and others). Чтобы вставить пример код, используйте <code lang="php">$a = "hello";</code> (поддерживаемые языки: ruby, php, yaml, html, csharp, javascript). Также Вы можете использовать <code>$a = "hello";</code>, синтаксис не будет подсвечен. Если вы не хотите использовать тег <code>, замените символ < на &lt;.

Отправить

 
Copyright © 2005 - 2008, Dmytro Shteflyuk