Я за свою сознательную жизнь написал с десяток классов для организации постраничего вывода на разных языках и под разные технологии. С приходом LINQ, в C# теперь можно сделать его универсальным. Я не претендую на абсолютную правильность изложенного, тем не менее, я гарантирую, что предложенные методы работают.
WCF и Paging
Допустим у нас есть страница, к базе данных которая подключена через WCF. IQueryable не сериализуется (ну и не надо, зачем нам писать логику построения запроса на уровне презентации), это значит нам надо передавать информацию о текущей странице через параметры. Значит нам нужен следующий класс:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization;
namespace MyService.Data
{
///
/// Used in PagingListPair by composition.
/// Or created directly from client side.
///
[DataContract]
[Serializable]
public class PagingInformation
{
///
///
///
page index to show
///
page size to show (amount of entries per page index)
///
static public PagingInformation CreateClientPaging(int index, int size)
{
var pageInfo = new PagingInformation();
pageInfo.PageIndex = index;
pageInfo.RecordsPerPage = size;
return pageInfo;
}
///
///
[DataMember]
public long? Count { get; set; }
///
///
[DataMember]
public int? RecordsPerPage { get; set; }
///
///
[DataMember]
public int? PageIndex { get; set; }
///
///
public int PageCount
{
get
{
if (!Count.HasValue || !RecordsPerPage.HasValue)
{
throw new InvalidOperationException("Invalid initialization of count or recordsAmount value");
}
decimal numOfPages = (decimal)Count.Value / (decimal)RecordsPerPage.Value;
numOfPages = Math.Ceiling(numOfPages);
return (int)numOfPages;
//return (int)Math.Round((decimal)(tmpCount / tmpRecPerPage), MidpointRounding.AwayFromZero);
//return (int)Math.Ceiling((decimal)(Count.Value / RecordsPerPage.Value));
}
}
}
}
Теперь на стороне клиента можно использовать CreateClientPaging, для того чтобы получить информацию о страницах и сами данные нам нужен композитный класс, который будет передаватся в качестве ответа:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization;
namespace MyService.Data
{
///
/// Holds paging information performed to query.
/// Used by
///
/// [DataMember] [DataMember] Вот и все, добавляем к нашему контракту аттрибуты: А в методах сервиса используем методы следующего формата: Для LINQ пейджинга можно использовать метод помошник: В ASP.NET есть интерфейс IPageableItemContainer, он используется в DataBinging public event EventHandler TotalRowCountAvailable; public void SetPageProperties(int startRowIndex, int maximumRows, bool databind) Onload*** Это PagingControl который можно использовать на страницах с простой логикой, класс можно переопределить для локализации и переопределения стилей, изменение текущей страницы можно получить после срабатывания события: namespace MyControls public event EventHandler PageIndexChanged; public int CurrentPageIndex ViewState["CurrentPageIndex"] = value; ViewState["PageCount"] = value; int pageButtonCount = 3; bool showPrevNext = true; protected virtual string GetItemStyle(int index) private void AddSpecialItem(SpecialPagingButtons type) { protected override void CreateChildControls() var range = CalculateRange(); if (CurrentPageIndex > 0 && ShowFirstLast) AddSpecialItem(SpecialPagingButtons.First); foreach (int i in range) if (CurrentPageIndex "); void specLinkButton_Click(object sender, EventArgs e) switch (btn) CreateChildControls(); void linkButton_Click(object sender, EventArgs e) CreateChildControls(); public int[] CalculateRange() if (PageCount <= PageButtonCount) if (CurrentPageIndex + pagesRight > (PageCount - 1)) if (pagesLeft + pagesRight == PageButtonCount) pagesRight--; start = CurrentPageIndex - pagesLeft; int[] result = new int[(end - start) + 1]; for (int i = start; i < end + 1; i++) return result; } Когда я познакомился с MVC, больше мне не хотелось изобретать велосипед, я нашел библиотеку PagedList. Реализация позожа на мой WCF Paging, пример кода можно посмотреть на основной странице проекта. Метки:ASP.NET, OpenSource, база данных
[DataContract]
[Serializable]
public class PagingListPair
{
///
///
public PagingInformation PagingInformation { get; set; }
public List
}
}
[ServiceKnownType(typeof(PagingInformation))]
[ServiceKnownType(typeof(MyEntity))]
[ServiceKnownType(typeof(PagingListPairPagingListPair public static PagingListPair
{
if (!pageInfo.PageIndex.HasValue || !pageInfo.RecordsPerPage.HasValue || !(pageInfo.RecordsPerPage.Value > 0))
{
throw new InvalidOperationException("Invalid pageInforation values");
}
pageInfo.Count = entities.Count();
var output = new PagingListPair
output.PagingInformation = pageInfo;
output.EntityList = entities.Skip(pageInfo.PageIndex.Value * pageInfo.RecordsPerPage.Value).Take(pageInfo.RecordsPerPage.Value).ToList();
return output;
}
ASP.NET стандартный пейджинг
Его реализация выглядит примерно так:
int _startIndex, _maxRows;
public int MaximumRows
{
get { return _maxRows; }
}
public int StartRowIndex
{
get { return _startIndex; }
}
{
_startIndex = startRowIndex;
_maxRows = maximumRows;
}
{
if (TotalRowCountAvailable != null)
{
TotalRowCountAvailable(this, new PageEventArgs(_startIndex, _maxRows, _dataSource.Count));
_dataSource = _dataSource.Skip(_startIndex).Take(_maxRows).ToList();
}
}Еще один метод постраничного вывода в качестве ASP.NET контрола.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
{
public enum SpecialPagingButtons
{
Prev, Next, First, Last
}
public class ResultListPager : Control, INamingContainer
{
public static int PageCountFromItems(int itemCount, int itemsPerPage) {
return (int)Math.Ceiling((0.0+itemCount)/itemsPerPage);
}
private void OnPageIndexChanged()
{
if (PageIndexChanged != null)
{
PageIndexChanged(this, EventArgs.Empty);
}
}
{
get
{
if (ViewState["CurrentPageIndex"] == null)
ViewState["CurrentPageIndex"] = 0;
return (int)ViewState["CurrentPageIndex"];
}
set
{
if (CurrentPageIndex != value)
{
if ((value < 0) && (PageCount > 1))
{
throw new Exception("CurrentPageIndex must be greater than -1 if PagesCount is greater than 0");
}
if ((value > (PageCount - 1)) || (value < 0))
{
throw new Exception("CurrentPageIndex is out of range");
}
}
}
}
public int PageCount
{
get
{
if (ViewState["PageCount"] == null)
ViewState["PageCount"] = 0;
return (int)ViewState["PageCount"];
}
set
{
if (PageCount != value)
{
if (value < 0)
{
throw new Exception("PageCount can not be smaller than zero.");
}
}
}
}
public int PageButtonCount
{
get
{
return pageButtonCount;
}
set
{
if (value < 3)
{
throw new Exception("PageButtonCount can not be smaller than 3");
}
pageButtonCount = value;
}
}
public bool ShowPrevNext
{
get { return showPrevNext; }
set { showPrevNext = value; }
}
bool showFirstLast = true;
public bool ShowFirstLast
{
get { return showFirstLast; }
set { showFirstLast = value; }
}
{
return (index == CurrentPageIndex)?"item-selected":"item";
}
protected virtual LinkButton CreateItem(string id, int idd)
{
return new LinkButton()
{
Text = (idd+1).ToString(),
CssClass = GetItemStyle(idd)
};
}
protected virtual LinkButton CreateSpacialItem(string id, SpecialPagingButtons btn)
{
var ret = new LinkButton();
switch (btn)
{
case SpecialPagingButtons.Prev:
ret.Text = "<";
ret.CssClass = GetItemStyle(CurrentPageIndex - 1);
break;
case SpecialPagingButtons.Next:
ret.Text = ">";
ret.CssClass = GetItemStyle(CurrentPageIndex + 1);
break;
case SpecialPagingButtons.First:
ret.Text = "«";
ret.CssClass = GetItemStyle(0);
break;
case SpecialPagingButtons.Last:
ret.Text = "»";
ret.CssClass = GetItemStyle(PageCount-1);
break;
default:
break;
}
return ret;
}
var id = "pg_" + type.ToString();
var linkButton = CreateSpacialItem(id, type);
linkButton.ID = id;
linkButton.Click += new EventHandler(specLinkButton_Click);
this.Controls.Add(linkButton);
}
{
this.Controls.Clear();
this.ClearChildViewState();
if (range.Length <= 1) return;
if (CurrentPageIndex > 0 && ShowPrevNext) AddSpecialItem(SpecialPagingButtons.Prev);
{
var id = "pg_" + i.ToString();
var linkButton = CreateItem(id, i);
linkButton.ID = id;
linkButton.Click += new EventHandler(linkButton_Click);
this.Controls.Add(linkButton);
}
//base.CreateChildControls();
}
protected override void Render(HtmlTextWriter writer)
{
if (this.Controls.Count > 0)
{
writer.Write("
base.Render(writer);
writer.Write("
}
}
{
var btn = (SpecialPagingButtons)Enum.Parse(typeof(SpecialPagingButtons), (sender as LinkButton).ID.Substring(3));
{
case SpecialPagingButtons.Prev:
if (CurrentPageIndex > 0) CurrentPageIndex--;
break;
case SpecialPagingButtons.Next:
if (CurrentPageIndex < PageCount-1) CurrentPageIndex++;
break;
case SpecialPagingButtons.First:
CurrentPageIndex = 0;
break;
case SpecialPagingButtons.Last:
CurrentPageIndex = PageCount - 1;
break;
default:
break;
}
OnPageIndexChanged();
}
{
CurrentPageIndex = Int32.Parse((sender as LinkButton).ID.Substring(3));
OnPageIndexChanged();
}
{
int end, start;
{
start = 0;
end = PageCount - 1;
}
else
{
int pagesLeft = (PageButtonCount - 1) / 2;
int pagesRight = (PageButtonCount - pagesLeft);
{
pagesRight = (PageCount - 1) - CurrentPageIndex;
pagesLeft = (PageButtonCount - pagesRight) - 1;
}
else
{
if (CurrentPageIndex - pagesLeft < 0)
{
pagesLeft = CurrentPageIndex;
pagesRight = (PageButtonCount - pagesLeft) - 1;
}
}
end = CurrentPageIndex + pagesRight;
}
int a = 0;
{
result[a] = i;
a++;
}
}
}
Paging в ASP.NET MVC
Похожие статьи
- 30 декабря 2008 -- Создаем ASHX хендлер в ASP.NET (1)
- 18 декабря 2008 -- Транслитерация RUS 2 LAT на C# (11)
- 22 августа 2008 -- Собственная страница для обработки ошибок на ASP.NET (0)
- 4 февраля 2009 -- LINQ Insert or Update еще одно решение. (0)
- 12 февраля 2010 -- Так ли хорош ASP.NET MVC? (7)



9 декабря, 2009 at 22:32
Как толково написано, я ввоссторге от статьи.
15 февраля, 2010 at 22:53
Полезная статья, думаю что обязательно пригодится.