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.
0 comments:
Post a Comment