I've been working on a Stack Overflow like pager for my personal use and I've gotten everything working pretty good. Some of my logic is a bit suspect though, especially the logic in the Pager class itself. I thought I'd try posting this code on here just to see what sort of responses I got. I included my test cases as well. Some of the test names might be weird, but I'll go back and fix that later. public class Pager { public int TotalPages { get; private set; } public int SelectedItem { get; private set; } public int PageNumbersToShow { get; set; } public string CssClass { get; set; } public Pager(int selectedItem, int totalPages, int pageNumbersToShow = 5) { this.SelectedItem = selectedItem; this.TotalPages = totalPages; this.PageNumbersToShow = pageNumbersToShow; this.CssClass = "pager fl"; } public override string ToString() { var finalString = new StringBuilder(); var pagerDiv = new TagBuilder("div"); pagerDiv.AddCssClass(CssClass); //prev 1 2 (3) //prev 1 (2) 3 next // (1) 2 3 next if (TotalPages <= PageNumbersToShow) { for (int i = 1; i <= TotalPages; i++) { finalString.Append(new PageNumber(i, (SelectedItem == i)).ToString()); } } //Greater than pagesize and selected page is less than pagesize // prev (1) 2 3 4 5 ... 11 next // prev 1 (2) 3 4 5 ... 11 next if (SelectedItem < PageNumbersToShow && TotalPages > PageNumbersToShow) { for (int i = 1; i <= PageNumbersToShow; i++) { finalString.Append(new PageNumber(i, (SelectedItem == i)).ToString()); } finalString.Append(new PageNumber().ToString()); finalString.Append(new PageNumber(TotalPages).ToString()); } //prev 1 ... 7 8 9 10 (11) //prev 1 ... 7 (8) 9 10 11 next if (SelectedItem > PageNumbersToShow && TotalPages - (PageNumbersToShow - 1) < SelectedItem) { finalString.Append(new PageNumber(1).ToString()); finalString.Append(new PageNumber().ToString()); for (int i = (TotalPages - PageNumbersToShow) + 1; i <= TotalPages; i++) { finalString.Append(new PageNumber(i, (SelectedItem == i)).ToString()); } } //prev 1 ... 4 5 (6) 7 8 ... 11 next if (SelectedItem >= PageNumbersToShow && TotalPages - (PageNumbersToShow - 1) >= SelectedItem) { finalString.Append(new PageNumber(1).ToString()); finalString.Append(new PageNumber().ToString()); var middle = (PageNumbersToShow / 2); for (int i = SelectedItem - middle; i <= SelectedItem + middle; i++) { finalString.Append(new PageNumber(i, (SelectedItem == i)).ToString()); } finalString.Append(new PageNumber().ToString()); finalString.Append(new PageNumber(TotalPages).ToString()); } /* Add Previous and Next Link */ if (SelectedItem != 1) { finalString.Insert(0, new PageNumber(SelectedItem - 1, "prev").ToString()); } if (SelectedItem != TotalPages) { finalString.Append(new PageNumber(SelectedItem + 1, "next").ToString()); } /* Copy final string into div inner HTML */ pagerDiv.InnerHtml = finalString.ToString(); return pagerDiv.ToString(); } private class PageNumber { private const string cssClass = "page-numbers"; private const string href = "?page={0}"; private TagBuilder link = new TagBuilder("a"); private TagBuilder span = new TagBuilder("span"); public bool Current { get; private set; } public int Page { get; private set; } public PageNumber(int Page, bool Current = false) { this.Current = Current; this.Page = Page; span.AddCssClass(cssClass); span.SetInnerText(Page.ToString()); } public PageNumber(int Page, string spanText) { this.Page = Page; span.AddCssClass(cssClass + " " + spanText); span.SetInnerText(spanText + " "); } public PageNumber() { span.AddCssClass(cssClass + " " + "dots"); span.SetInnerText("..."); } public override string ToString() { if (Current) { span.AddCssClass("current"); return span.ToString(); } else { if (span.ToString().Contains("dots")) { return span.ToString(); } link.MergeAttribute("href", string.Format(href, Page)); link.MergeAttribute("title", string.Format("go to page {0}", Page)); link.InnerHtml = span.ToString(); return link.ToString(); } } } } [TestClass] public class PagerTests { // (1) [TestMethod] public void Should_Only_Print_Out_One_Span_If_Number_Of_Pages_Is_One() { //Arrange var pager = new Pager(1, 1); //Act var result = pager.ToString(); //Assert result.ShouldEqual(@"<div class=""pager fl""><span class=""current page-numbers"">1</span></div>"); } // (1) 2 3 next [TestMethod] public void Should_Not_Print_Out_Previous_If_Selected_Page_Is_First_In_List_Smaller_Than_Five() { //Arrange StringBuilder expectedValue = new StringBuilder(); var pager = new Pager(1, 3); //Act var result = pager.ToString(); //Assert expectedValue.Append(@"<div class=""pager fl"">"); expectedValue.Append(@"<span class=""current page-numbers"">1</span>"); expectedValue.Append(@"<a href=""?page=2"" title=""go to page 2""><span class=""page-numbers"">2</span></a>"); expectedValue.Append(@"<a href=""?page=3"" title=""go to page 3""><span class=""page-numbers"">3</span></a>"); expectedValue.Append(@"<a href=""?page=2"" title=""go to page 2""><span class=""page-numbers next"">next </span></a>"); expectedValue.Append(@"</div>"); result.ShouldEqual(expectedValue.ToString()); } // prev 1 2 (3) [TestMethod] public void Should_Not_Print_Out_Next_Link_When_Selected_Page_Is_Last_In_List_Smaller_Than_Five() { //Arrange StringBuilder expectedValue = new StringBuilder(); var pager = new Pager(3, 3); //Act var result = pager.ToString(); //Assert expectedValue.Append(@"<div class=""pager fl"">"); expectedValue.Append(@"<a href=""?page=2"" title=""go to page 2""><span class=""page-numbers prev"">prev </span></a>"); expectedValue.Append(@"<a href=""?page=1"" title=""go to page 1""><span class=""page-numbers"">1</span></a>"); expectedValue.Append(@"<a href=""?page=2"" title=""go to page 2""><span class=""page-numbers"">2</span></a>"); expectedValue.Append(@"<span class=""current page-numbers"">3</span>"); expectedValue.Append(@"</div>"); result.ShouldEqual(expectedValue.ToString()); } // prev 1 (2) 3 next [TestMethod] public void Should_Print_Out_Both_Next_And_Previous_When_Selected_Is_Not_First_Or_Last_In_List_Smaller_Than_Five() { //Arrange StringBuilder expectedValue = new StringBuilder(); var pager = new Pager(2, 3); //Act var result = pager.ToString(); //Assert expectedValue.Append(@"<div class=""pager fl"">"); expectedValue.Append(@"<a href=""?page=1"" title=""go to page 1""><span class=""page-numbers prev"">prev </span></a>"); expectedValue.Append(@"<a href=""?page=1"" title=""go to page 1""><span class=""page-numbers"">1</span></a>"); expectedValue.Append(@"<span class=""current page-numbers"">2</span>"); expectedValue.Append(@"<a href=""?page=3"" title=""go to page 3""><span class=""page-numbers"">3</span></a>"); expectedValue.Append(@"<a href=""?page=3"" title=""go to page 3""><span class=""page-numbers next"">next </span></a>"); expectedValue.Append(@"</div>"); result.ShouldEqual(expectedValue.ToString()); } // (1) 2 3 4 5 ... 11 next [TestMethod] public void List_Greater_Than_Five_Pages_Generates_Dot_Dot_Dot_Last_Link_With_Page_One_Selcted() { //Arrange StringBuilder expectedValue = new StringBuilder(); var pager = new Pager(1, 11); //Act var result = pager.ToString(); //Assert expectedValue.Append(@"<div class=""pager fl"">"); expectedValue.Append(@"<span class=""current page-numbers"">1</span>"); expectedValue.Append(@"<a href=""?page=2"" title=""go to page 2""><span class=""page-numbers"">2</span></a>"); expectedValue.Append(@"<a href=""?page=3"" title=""go to page 3""><span class=""page-numbers"">3</span></a>"); expectedValue.Append(@"<a href=""?page=4"" title=""go to page 4""><span class=""page-numbers"">4</span></a>"); expectedValue.Append(@"<a href=""?page=5"" title=""go to page 5""><span class=""page-numbers"">5</span></a>"); expectedValue.Append(@"<span class=""page-numbers dots"">...</span>"); expectedValue.Append(@"<a href=""?page=11"" title=""go to page 11""><span class=""page-numbers"">11</span></a>"); expectedValue.Append(@"<a href=""?page=2"" title=""go to page 2""><span class=""page-numbers next"">next </span></a>"); expectedValue.Append(@"</div>"); result.ShouldEqual(expectedValue.ToString()); } // prev 1 ... 3 4 (5) 6 7 ... 11 next [TestMethod] public void List_Greater_Than_Five_Give_Prev_One_Dot_Dot_Dot_Four_Numbers_Dot_Dot_Dot_Last_Next() { //Arrange StringBuilder expectedValue = new StringBuilder(); var pager = new Pager(5, 11); //Act var result = pager.ToString(); //Assert expectedValue.Append(@"<div class=""pager fl"">"); expectedValue.Append(@"<a href=""?page=4"" title=""go to page 4""><span class=""page-numbers prev"">prev </span></a>"); expectedValue.Append(@"<a href=""?page=1"" title=""go to page 1""><span class=""page-numbers"">1</span></a>"); expectedValue.Append(@"<span class=""page-numbers dots"">...</span>"); expectedValue.Append(@"<a href=""?page=3"" title=""go to page 3""><span class=""page-numbers"">3</span></a>"); expectedValue.Append(@"<a href=""?page=4"" title=""go to page 4""><span class=""page-numbers"">4</span></a>"); expectedValue.Append(@"<span class=""current page-numbers"">5</span>"); expectedValue.Append(@"<a href=""?page=6"" title=""go to page 6""><span class=""page-numbers"">6</span></a>"); expectedValue.Append(@"<a href=""?page=7"" title=""go to page 7""><span class=""page-numbers"">7</span></a>"); expectedValue.Append(@"<span class=""page-numbers dots"">...</span>"); expectedValue.Append(@"<a href=""?page=11"" title=""go to page 11""><span class=""page-numbers"">11</span></a>"); expectedValue.Append(@"<a href=""?page=6"" title=""go to page 6""><span class=""page-numbers next"">next </span></a>"); expectedValue.Append(@"</div>"); result.ShouldEqual(expectedValue.ToString()); } // prev 1 ... 7 8 9 10 (11) [TestMethod] public void When_List_Is_Greater_Than_Five_And_Selected_Is_The_Last_Item() { //Arrange StringBuilder expectedValue = new StringBuilder(); var pager = new Pager(11, 11); //Act var result = pager.ToString(); //Assert expectedValue.Append(@"<div class=""pager fl"">"); expectedValue.Append(@"<a href=""?page=10"" title=""go to page 10""><span class=""page-numbers prev"">prev </span></a>"); expectedValue.Append(@"<a href=""?page=1"" title=""go to page 1""><span class=""page-numbers"">1</span></a>"); expectedValue.Append(@"<span class=""page-numbers dots"">...</span>"); expectedValue.Append(@"<a href=""?page=7"" title=""go to page 7""><span class=""page-numbers"">7</span></a>"); expectedValue.Append(@"<a href=""?page=8"" title=""go to page 8""><span class=""page-numbers"">8</span></a>"); expectedValue.Append(@"<a href=""?page=9"" title=""go to page 9""><span class=""page-numbers"">9</span></a>"); expectedValue.Append(@"<a href=""?page=10"" title=""go to page 10""><span class=""page-numbers"">10</span></a>"); expectedValue.Append(@"<span class=""current page-numbers"">11</span>"); expectedValue.Append(@"</div>"); result.ShouldEqual(expectedValue.ToString()); } // prev 1 ... 7 (8) 9 10 11 next [TestMethod] public void When_List_Is_Greater_Than_Five_And_Within_PageSize_Of_End_Of_List_And_Last_Item_Is_Not_Selected() { //Arrange StringBuilder expectedValue = new StringBuilder(); var pager = new Pager(8, 11); //Act var result = pager.ToString(); //Assert expectedValue.Append(@"<div class=""pager fl"">"); expectedValue.Append(@"<a href=""?page=7"" title=""go to page 7""><span class=""page-numbers prev"">prev </span></a>"); expectedValue.Append(@"<a href=""?page=1"" title=""go to page 1""><span class=""page-numbers"">1</span></a>"); expectedValue.Append(@"<span class=""page-numbers dots"">...</span>"); expectedValue.Append(@"<a href=""?page=7"" title=""go to page 7""><span class=""page-numbers"">7</span></a>"); expectedValue.Append(@"<span class=""current page-numbers"">8</span>"); expectedValue.Append(@"<a href=""?page=9"" title=""go to page 9""><span class=""page-numbers"">9</span></a>"); expectedValue.Append(@"<a href=""?page=10"" title=""go to page 10""><span class=""page-numbers"">10</span></a>"); expectedValue.Append(@"<a href=""?page=11"" title=""go to page 11""><span class=""page-numbers"">11</span></a>"); expectedValue.Append(@"<a href=""?page=9"" title=""go to page 9""><span class=""page-numbers next"">next </span></a>"); expectedValue.Append(@"</div>"); result.ShouldEqual(expectedValue.ToString()); } //prev 1 ... 5 6 (7) 8 9 ... 11 next [TestMethod] public void When_Selected_Is_One_Less_Than_Page_Size() { //Arrange StringBuilder expectedValue = new StringBuilder(); var pager = new Pager(7, 11); //Act var result = pager.ToString(); //Assert expectedValue.Append(@"<div class=""pager fl"">"); expectedValue.Append(@"<a href=""?page=6"" title=""go to page 6""><span class=""page-numbers prev"">prev </span></a>"); expectedValue.Append(@"<a href=""?page=1"" title=""go to page 1""><span class=""page-numbers"">1</span></a>"); expectedValue.Append(@"<span class=""page-numbers dots"">...</span>"); expectedValue.Append(@"<a href=""?page=5"" title=""go to page 5""><span class=""page-numbers"">5</span></a>"); expectedValue.Append(@"<a href=""?page=6"" title=""go to page 6""><span class=""page-numbers"">6</span></a>"); expectedValue.Append(@"<span class=""current page-numbers"">7</span>"); expectedValue.Append(@"<a href=""?page=8"" title=""go to page 8""><span class=""page-numbers"">8</span></a>"); expectedValue.Append(@"<a href=""?page=9"" title=""go to page 9""><span class=""page-numbers"">9</span></a>"); expectedValue.Append(@"<span class=""page-numbers dots"">...</span>"); expectedValue.Append(@"<a href=""?page=11"" title=""go to page 11""><span class=""page-numbers"">11</span></a>"); expectedValue.Append(@"<a href=""?page=8"" title=""go to page 8""><span class=""page-numbers next"">next </span></a>"); expectedValue.Append(@"</div>"); result.ShouldEqual(expectedValue.ToString()); } //prev 1 ... 8 9 (10) 11 12 ... 15 next [TestMethod] public void When_Selected_Is_Exactly_Total_Pages_Minus_Page_Size() { //Arrange StringBuilder expectedValue = new StringBuilder(); var pager = new Pager(10, 15); //Act var result = pager.ToString(); //Assert expectedValue.Append(@"<div class=""pager fl"">"); expectedValue.Append(@"<a href=""?page=9"" title=""go to page 9""><span class=""page-numbers prev"">prev </span></a>"); expectedValue.Append(@"<a href=""?page=1"" title=""go to page 1""><span class=""page-numbers"">1</span></a>"); expectedValue.Append(@"<span class=""page-numbers dots"">...</span>"); expectedValue.Append(@"<a href=""?page=8"" title=""go to page 8""><span class=""page-numbers"">8</span></a>"); expectedValue.Append(@"<a href=""?page=9"" title=""go to page 9""><span class=""page-numbers"">9</span></a>"); expectedValue.Append(@"<span class=""current page-numbers"">10</span>"); expectedValue.Append(@"<a href=""?page=11"" title=""go to page 11""><span class=""page-numbers"">11</span></a>"); expectedValue.Append(@"<a href=""?page=12"" title=""go to page 12""><span class=""page-numbers"">12</span></a>"); expectedValue.Append(@"<span class=""page-numbers dots"">...</span>"); expectedValue.Append(@"<a href=""?page=15"" title=""go to page 15""><span class=""page-numbers"">15</span></a>"); expectedValue.Append(@"<a href=""?page=11"" title=""go to page 11""><span class=""page-numbers next"">next </span></a>"); expectedValue.Append(@"</div>"); result.ShouldEqual(expectedValue.ToString()); } }