Adaptive/dynamic page numbering in c#

If you need to show many results (tens, hundreds or thousands), in a paged manner, you won’t want to display links to all those pages. I looked online for some c# that would adapt the number of page links shown to with the number of pages returned, but found nothing.

If you get 5 pages of results, show them all. If you get 5,000 pages of results, show some around your current page and less and less the further you get from your current page.

This is something I put together in an hour, I make no claims about its efficiency and there are scenarios that are not catered for (like higher current page than the total number of pages).

Here are some examples of what this code does.

Current Page:1 Total Pages:40 Pages to display around current page:5
1 2 3 4 5 6 7 8 9 10 11 20 30 40

Current Page:90 Total Pages:600 Pages to display around current page:5
1 40 50 60 70 80 85 86 87 88 89 90 91 92 93 94 95 100 110 120 130 140 200 300 400 500 600

Current Page:147 Total Pages:6825 Pages to display around current page:5
1 90 100 110 120 130 140 142 143 144 145 146 147 148 149 150 151 152 160 170 180 190 200 300 400 500 600 700 800 900 1000 1100 2000 3000 4000 5000 6000 6825

You could easily change the code to take a Page type to suit your own needs.

Here’s the code.

namespace NoDogmaBlog
{
    public class PagingHelper
    {
        public IEnumerable<int> GetListOfPages(int currentPage, int pagesAroundCurrent, int totalPages)
        {
            var pages = new Dictionary<int, int>();
            double powerOfTenTotalPages = Math.Floor(Math.Log10(totalPages));
            if ((int)powerOfTenTotalPages == 0)
            {
                powerOfTenTotalPages = 1;
            }
            pages.Add(1, 1);
            if (!pages.ContainsKey(totalPages))
            {
                pages.Add(totalPages, totalPages);
            }

            for (int loop = 1; loop <= powerOfTenTotalPages + 1; loop++)
            {
                GetPages(pages, currentPage, pagesAroundCurrent, totalPages, (int)Math.Pow(10, loop - 1));
            }
            return pages.OrderBy(k=>k.Key).Select(p=>p.Key).AsEnumerable();
        }

        private void GetPages(Dictionary<int, int> pages, int currentPage, int pagesAroundCurrent, int totalPages, int jump)
        {
            int startPage = ((currentPage / jump) * jump) - (pagesAroundCurrent * jump);

            if (startPage < 0)
            {
                startPage = 0;
                pagesAroundCurrent = 10;
            }

            int endPage = currentPage + (pagesAroundCurrent * jump);
            if (endPage > totalPages)
            {
                endPage = totalPages;
            }
            AddPagesToDict(pages, startPage, endPage, jump);
        }

        private void AddPagesToDict(Dictionary<int, int> pages, int start, int end, int jump)
        {
            for (int loop = start; loop <= end; loop += jump)
            {
                if (!pages.ContainsKey(loop))
                {
                    if (loop > 0)
                    {
                        pages.Add(loop, loop);
                    }
                }
            }
        }
    }
}