Показ страниц пагинации

115
08 ноября 2019, 15:40

Есть у меня код, который выводит пагинацию на странице:

Это выводятся все элементы как есть - от первого до MaxPage:

@if (Model.IsFirst())
{
    <li class="page-item disabled"><a class="page-link" href="@Model.GetUrl(1)"><<</a></li>
    <li class="page-item disabled"><a class="page-link" href="@Model.GetUrl(Model.PageNumber - 1)"><</a></li>
}
else
{
    <li class="page-item"><a class="page-link" href="@Model.GetUrl(1)"><<</a></li>
    <li class="page-item"><a class="page-link" href="@Model.GetUrl(Model.PageNumber - 1)"><</a></li>
}
@for (var i = 1; i <= Model.MaxPageCount; i++)
{
    if (Model.IsCurrent(i))
    {
        <li class="page-item active">
            <a class="page-link disabled" href="@Model.GetUrl(i)">@i</a>
        </li>
    }
    else
    {
        <li class="page-item">
            <a class="page-link" href="@Model.GetUrl(i)">@i</a>
        </li>
    }
}

Проблемы начинаются, когда число страниц становится больше 10 (а частенько в пагинации и по триста страниц бывает) - они улетают за правую границу экрана.

Сижу думаю, какое условие нужно взять чтобы пагинация показывалась красиво.

Попробуем формализовать условие. Есть некоторая IEnumerable<int> от 1 до Model.MaxPageCount и есть некоторое число PageNumber (текущий номер страницы) которое принадлежит этой последовательности.

Не уверен точно, но допустим мне надо получить не более пяти элементов ДО текущей страницы и не более пяти элементов ПОСЛЕ текущей страницы.

При этом я не знаю, как красиво обработать ситуацию, что если страниц ДО не хватает (допустим, мы смотрим страницу 3, тогда ДО будут страницы 1 и 2) то после наверное стоит взять чуть больше - не пять, а на на три больше. Но и не факт, что ПОСЛЕ хватит нужного числа страниц.

Вопрос скорее на красивый и простой алгоритм (как это принято делать в типичных пагинаторах?), возможно что конкретную формулу я и сам напишу. Если кто сталивался с подобной задачей и знает, как такое можно сделать - предложите вариант. Я смотрел разные варианты XPagedList на github, но какого-то удобного варианта не нашёл.

Answer 1

Что то типа такого?

List<int> GeneratePages(int currentPage, int totalPages)
{
    var pages = new List<int>();
    for(var i=currentPage; i>0 && i>=currentPage-5; i--) pages.Add(i);
    pages.Reverse();    
    for(var i=currentPage+1; i<=totalPages && i<=currentPage+5; i++) pages.Add(i);
    return pages;
}

Проверка

Console.WriteLine( string.Join(",", GeneratePages(50, 100)));
Console.WriteLine( string.Join(",", GeneratePages(1, 100)));
Console.WriteLine( string.Join(",", GeneratePages(2, 100)));
Console.WriteLine( string.Join(",", GeneratePages(98, 100)));
Console.WriteLine( string.Join(",", GeneratePages(99, 100)));
Console.WriteLine( string.Join(",", GeneratePages(100, 100)));

Результаты

45,46,47,48,49,50,51,52,53,54,55
1,2,3,4,5,6
1,2,3,4,5,6,7
93,94,95,96,97,98,99,100
94,95,96,97,98,99,100
95,96,97,98,99,100 

Если, например, хочется видеть в сумме 11 элементов (то есть в идеале 5 слева, 5 спава, 1 текущий) и адаптировать при сдвигах (2 слева, 1 текущий, 8 справа - для страницы номер 3), то ваот второй вариант

List<int> GeneratePages(int currentPage, int totalPages, int expectedpages)
{
    var beforeCurrent = new Stack<int>();
    var afterCurrent = new Queue<int>();
    var expected = expectedpages - 1;
    var i = currentPage-1;
    var j = currentPage+1;
    while(expected > 0)
    {
        var local = expected;
        if (i > 0) {
            beforeCurrent.Push(i);
            i--;
            expected--;
        }
        if (j<=totalPages && expected > 0)
        {
            afterCurrent.Enqueue(j);
            j++;
            expected--;
        }
        if (local == expected) break;
    }
    var res = new List<int>();
    while(beforeCurrent.Count>0) res.Add(beforeCurrent.Pop());
    res.Add(currentPage);
    while(afterCurrent.Count>0) res.Add(afterCurrent.Dequeue());
    return res;
}

Проверяем

Console.WriteLine( string.Join(",", GeneratePages(50, 100, 11)));
Console.WriteLine( string.Join(",", GeneratePages(1, 100, 11)));
Console.WriteLine( string.Join(",", GeneratePages(2, 100, 11)));
Console.WriteLine( string.Join(",", GeneratePages(98, 100, 11)));
Console.WriteLine( string.Join(",", GeneratePages(99, 100, 11)));
Console.WriteLine( string.Join(",", GeneratePages(100, 100, 11)));  
Console.WriteLine( string.Join(",", GeneratePages(2, 5, 11)));

Вывод

45,46,47,48,49,50,51,52,53,54,55
1,2,3,4,5,6,7,8,9,10,11
1,2,3,4,5,6,7,8,9,10,11
90,91,92,93,94,95,96,97,98,99,100
90,91,92,93,94,95,96,97,98,99,100
90,91,92,93,94,95,96,97,98,99,100
1,2,3,4,5    
Answer 2

Сделано по ответу @VladD:

void Main()
{
    var lastPage = 20;
    var currentPage = 3;
    var result = this.GetPaging(currentPage, lastPage);
    result.Dump();
}
IEnumerable<int> GetPaging(int currentPage, int lastPage)
{
    var maxBefore = 5;
    var maxAfter = 5;
    var first = currentPage - maxBefore;
    if(first < 1)
        first = 1;
    var last = currentPage + maxAfter;
    if(last > lastPage)
        last = lastPage;
    return Enumerable.Range(first, last - first);
}
READ ALSO
Вывод общего времени трека NAudio C#

Вывод общего времени трека NAudio C#

Необходимо выводить время трековПолучается сделать, если например только mp3

130
Проблема с Windows Forms

Проблема с Windows Forms

Есть написанная мною программа на c# и в ней есть цикл whileНо когда я запускают программу с этим циклом, то нет того окна которое я сделал

140
Microsoft Reporting Service и PDF 1.4

Microsoft Reporting Service и PDF 1.4

Есть какие-либо способы создать PDF версии 14 через Microsoft Reporting Services? У меня получается только версия 1

134
Исходный код программы

Исходный код программы

Выдали тз, с самим тз проблем нетТолько Вот один момент , цитирую "надо прислать исходный код и запускаемый файл

211