Tuesday, April 19, 2016

Paging in ASP.Net; the number of pages never changes after filtering

Leave a Comment

The issue comes when you open a page with only 1 record. It fills the NavMenu with 3 links; "First", "1" and "Last". For some reason, when you run a search query that will return more than one page, it still only displays "First", "1" and "Last". Similarly, if you start with 4 pages and your subsequent search query only returns 2 records, it still shows "First", "1", "2", "3", "4" and "Last". So, for some reason, however many pages you start with, you'll always get. How can you reset the page counter/display?

Here's my C# code-behind:

public void RunTheSearch() {     //Run the Stored Procedure first     SqlConnection connection2 = new SqlConnection(strCon1);     SqlCommand cmd2 = new SqlCommand();     cmd2.CommandType = CommandType.StoredProcedure;     cmd2.CommandText = "sp_Search";     cmd2.Connection = connection2;      //--- A bunch of code that returns a dataset.  Lengthy and unnecessary to my issue      connection2.Open();      SqlDataAdapter adp = new SqlDataAdapter(cmd2);       DataSet ds = new DataSet();     adp.Fill(ds, "OLDPages");      //Pagination code so only a set number of records loads at a time.     //  Done to speed up the loading, since this list gets really long.     PagedDataSource pds = new PagedDataSource();     pds.DataSource = ds.Tables["OLDPages"].DefaultView;      pds.AllowPaging = true;     pds.PageSize = 10;     //NavMenu.Items.Clear();      int currentPage;      if (Request.QueryString["page"] != null)     {     currentPage = Int32.Parse(Request.QueryString["page"]);     }     else     {     currentPage = 1;     }      pds.CurrentPageIndex = currentPage - 1;     //Label1.Text = "Page " + currentPage + " of " + pds.PageCount;       if (!pds.IsFirstPage)     {     MenuItem itemMessage = NavMenu.FindItem("First");     itemMessage.NavigateUrl = Request.CurrentExecutionFilePath + "?page=1";     }      AcctRepeater.DataSource = pds;     AcctRepeater.DataBind();      CreatePagingControl(pds.PageCount, pds.CurrentPageIndex);     // End of Pagination code      connection2.Close(); }  private void CreatePagingControl(int PCount, int PIndex) {     int PIndex2 = 0;     int SCounter = PIndex + 1;     int RowCount = PCount;      //Allow the pagination menu to always start 5 less than the current page you're on     if (PIndex < 5)     {     PIndex2 = 0;     }     else     {     PIndex2 = PIndex - 5;     }      // Show 10 total page numbers.  You can increase or shrink that range by changing the 10 to whatever number you want     for (int i = PIndex2; i < PIndex2 + 10 && i < PCount; i++)     {     NavMenu.Items.Add(new MenuItem     {         Text = (i + 1).ToString(),         NavigateUrl = Request.CurrentExecutionFilePath + "?page=" + (i + 1).ToString()     });      // Now determine the selected item so the proper CSS can be applied     foreach (MenuItem item in NavMenu.Items)     {         item.Selected = item.Text.Equals(SCounter.ToString());     }     }      NavMenu.Items.Add(new MenuItem     {     Text = "Last",     NavigateUrl = Request.CurrentExecutionFilePath + "?page=" + (PCount)     }); }          

And on the aspx page:

<asp:Menu ID="NavMenu" runat="server" CssClass="menu"  IncludeStyleBlock="false" Orientation="Horizontal" width="703px" BackColor="#CC3300" EnableViewState="true"> <Items>      <asp:MenuItem NavigateUrl="~/Default.aspx" Text="First" Selectable="true" /> </Items> </asp:Menu>  

I did try NavMenu.Items.Clear(), but it didn't like that because it also cleared out the hard-coded item on the aspx side.

4 Answers

Answers 1

I cannot reproduce it.

My intuition tells me you're not posting back and that's why you need to clear() the results.

This C# code works fine.

protected void Page_Load(object sender, EventArgs e) {     RunTheSearch(); } 

Answers 2

The only problem here is with ViewState. Items are persisted in ViewState, so if you press button causing PostBack twice the items are appended at the end of items that were appended previously.

If you change the <asp:Menu ... EnableViewState="false" /> you don't need clean the items anymore.

Alternatively (if you need ViewState enabled for some other reason) you can mark the items when you're adding them like:

NavMenu.Items.Add(new MenuItem {     //...     Value = "Paging" }); 

And instead of cleaning up all items clear just the marked ones:

 var removableItems = NavMenu.Items.Cast<MenuItem>()    .Where(i => i.Value == "Paging").ToList();  foreach (var removableItem in removableItems)  {    NavMenu.Items.Remove(removableItem);  }     

Answers 3

You are retrieving the data from a stored procedure named sp_Search but your query in all runs will be same because you didn't specify any parameters in your stored procedure (based on the code that you posted). I tested your code by modifying the stored procedure and send a parameter to it and also using NavMenu.Items.Clear() as you said and it works fine for me:

Your SP should be something like this:

CREATE PROCEDURE [dbo].[sp_Search]     @param1 NVARCHAR(50) AS     SELECT * from yourTableName where SearchField = @param1 RETURN 0 

And in c#:

public void RunTheSearch(string id) {     ...     cmd2.CommandType = CommandType.StoredProcedure;     cmd2.CommandText = "sp_Search";     cmd2.Parameters.Add("@param1", SqlDbType.NVarChar, 50).Value = id;     ...     ... 

So in your Page_Load call the RunTheSearch method by passing a parameter which returns one record:

protected void Page_Load(object sender, EventArgs e) {     RunTheSearch("p1");             } 

And somewhere else call the RunTheSearch method by passing a parameter which returns multiple record and result would be more than one page:

protected void Button1_OnClick(object sender, EventArgs e) {     NavMenu.Items.Clear();     RunTheSearch("p2"); } 

Answers 4

This was eventually solved by putting the menu in an Update panel. So, on the aspx side I now have:

<div class="clear hideSkiplink" id="NavDiv" style="margin:0 auto; display: table;">     <asp:UpdatePanel ID="NavUpdatePanel" runat="server" UpdateMode="Conditional">         <ContentTemplate>             <asp:Menu ID="NavMenu" runat="server" CssClass="menu"                  IncludeStyleBlock="false" Orientation="Horizontal" width="703px"                 BackColor="#CC3300" EnableViewState="false">                 <Items>                      <asp:MenuItem NavigateUrl="~/Default.aspx" Text="First" Selectable="true" />                 </Items>             </asp:Menu>         </ContentTemplate>     </asp:UpdatePanel> </div> 

Thank you everyone who gave it a go. It was actually while replying to the posts that a switch went on in my brain and I got the idea to try it.

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment