Custom Paging in Grid view
So, it takes too long for me to write this post. even though I completed the coding stuff a week back but it is really hard to manage time these days.
In this post, I will explain and demonstrate you how to create custom paging in Grid view control. Paging which works like the Google Paging. Let me elaborate more, say for example you have a record set of 500 items and you want to display 10 items per page. Now what happen to the pages numbers. Either you use the default with “..” sign after 10th page link which cause the post back and then get some new page numbers. Or you want to make it like Google. i.e as soon as user move forward on page index, hide the previous pages and show the new numbers and when user is getting back hide new numbers and show the previous page links. following image can give you some idea what we are going to do.
To start, lets first create a Grid view .
1: <asp:GridView ID="GridView1" runat="server" AllowPaging="True"
2: onrowcreated="GridView1_RowCreated" >
3: </asp:GridView>
Yes, we have allow the paging but we are not going to use the default paging of asp.net. That is why we have write onrowcreated implementation in which we will simply detect and hide the pager row.
1: protected void GridView1_RowCreated(object sender, GridViewRowEventArgs e)
2: {
3: if (e.Row.RowType == DataControlRowType.Pager)
4: {
5: e.Row.Visible = false;
6: }
7: }
Now lets move to some global variables which we need through out our code.
1: const int pageSize = 10;
2: const int pageDispCount = 10;
3: private DataTable dt = new DataTable();
pagesSize : number of records we want to display per page.
pageDispCount : number of page numbers we want to display on custom paging.
dt : A datatable which we will use to store data and use it on different post backs.
Ok, now we need to get data from database, dump it to datatable and define the datasource of grid view.
1: protected void bindData()
2: {
3: SqlConnection objSqlCon = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["AdventureWorksConnectionString"].ToString());
4: objSqlCon.Open();
5:
6: SqlDataAdapter objSqlDa = new SqlDataAdapter("select * from Production.Product", objSqlCon);
7:
8: objSqlDa.Fill(dt);
9:
10: GridView1.DataSource = dt;
11: GridView1.DataBind();
12:
13: managePaging(dt);
14: }
On line number 13, managePaging function will be used later to implement the paging logic. But before that, lets understand that we have taken the datatable as a global variable and each time after postback when we try to read our datatable we will get no results because there is no state management for this object.
So lets override the LoadViewState and SaveViewState function of System.Web.UI.Page to save and restore the datatable by using viewstate.
1: protected override object SaveViewState()
2: {
3: object baseState = base.SaveViewState();
4: return new object[] { baseState, dt };
5: }
6: protected override void LoadViewState(object savedState)
7: {
8: object[] myState = (object[])savedState;
9: if (myState[0] != null)
10: base.LoadViewState(myState[0]);
11:
12: if (myState[1] != null)
13: {
14: dt = (DataTable) myState[1];
15: GridView1.DataSource = dt;
16: GridView1.DataBind();
17:
18: managePaging(dt);
19: }
20:
21: }
Well, SaveViewState function is simply putting the base.SaveViewState object and datatable in and object and returning it. A Simple Logic :)
Where as, LoadViewState is retrieving and type casting the object exactly in the sequence it was save in the SaveViewState method.
1: protected void managePaging(DataTable _dt)
2: {
3: if (_dt.Rows.Count > 0)
4: {
5:
6: // Variable declaration
7: int numberOfPages;
8: int numberOfRecords = dt.Rows.Count;
9: int currentPage = (GridView1.PageIndex);
10: StringBuilder strSummary = new StringBuilder();
11:
12:
13: // If number of records is more then the page size (specified in global variable)
14: // Just to check either gridview have enough records to implement paging
15: if (numberOfRecords > pageSize)
16: {
17: // Calculating the total number of pages
18: numberOfPages = (int)Math.Ceiling((double)numberOfRecords / (double)pageSize);
19: }
20: else
21: {
22: numberOfPages = 1;
23: }
24:
25:
26: // Creating a small summary for records.
27: strSummary.Append("Displaying <b>");
28:
29: // Creating X f X Records
30: int floor = (currentPage * pageSize) + 1;
31: strSummary.Append(floor.ToString());
32: strSummary.Append("</b>-<b>");
33: int ceil = ((currentPage * pageSize) + pageSize);
34:
35: //let say you have 26 records and you specified 10 page size,
36: // On the third page it will return 30 instead of 25 as that is based on pageSize
37: // So this check will see if the ceil value is increasing the number of records. Consider numberOfRecords
38: if (ceil > numberOfRecords)
39: {
40: strSummary.Append(numberOfRecords.ToString());
41: }
42: else
43: {
44: strSummary.Append(ceil.ToString());
45: }
46:
47: // Displaying Total number of records Creating X of X of About X records.
48: strSummary.Append("</b> of About <b>");
49: strSummary.Append(numberOfRecords.ToString());
50: strSummary.Append("</b>Records</br>");
51:
52:
53: litPagingSummary.Text = strSummary.ToString();
54:
55:
56: //Variable declaration
57: //these variables will used to calculate page number display
58: int pageShowLimitStart = 1;
59: int pageShowLimitEnd = 1;
60:
61:
62:
63: // Just to check, either there is enough pages to implement page number display logic.
64: if (pageDispCount > numberOfPages)
65: {
66: pageShowLimitEnd = numberOfPages; // Setting the end limit to the number of pages. Means show all page numbers
67: }
68: else
69: {
70: if (currentPage > 4) // If page index is more then 4 then need to less the page numbers from start and show more on end.
71: {
72: //Calculating end limit to show more page numbers
73: pageShowLimitEnd = currentPage + (int)(Math.Floor((decimal)pageDispCount / 2));
74: //Calculating Start limit to hide previous page numbers
75: pageShowLimitStart = currentPage - (int)(Math.Floor((decimal)pageDispCount / 2));
76: }
77: else
78: {
79: //Simply Displaying the 10 pages. no need to remove / add page numbers
80: pageShowLimitEnd = pageDispCount;
81: }
82: }
83:
84: // Since the pageDispCount can be changed and limit calculation can cause < 0 values
85: // Simply, set the limit start value to 1 if it is less
86: if (pageShowLimitStart < 1)
87: pageShowLimitStart = 1;
88:
89:
90: //Dynamic creation of link buttons
91:
92: // First Link button to display with paging
93: LinkButton objLbFirst = new LinkButton();
94: objLbFirst.Click += new EventHandler(objLb_Click);
95: objLbFirst.Text = "First";
96: objLbFirst.ID = "lb_FirstPage";
97: objLbFirst.CommandName = "pgChange";
98: objLbFirst.EnableViewState = true;
99: objLbFirst.CommandArgument = "1";
100:
101: //Previous Link button to display with paging
102: LinkButton objLbPrevious = new LinkButton();
103: objLbPrevious.Click += new EventHandler(objLb_Click);
104: objLbPrevious.Text = "Previous";
105: objLbPrevious.ID = "lb_PreviousPage";
106: objLbPrevious.CommandName = "pgChange";
107: objLbPrevious.EnableViewState = true;
108: objLbPrevious.CommandArgument = currentPage.ToString();
109:
110:
111: //of course if the page is the 1st page, then there is no need of First or Previous
112: if (currentPage == 0)
113: {
114: objLbFirst.Enabled = false;
115: objLbPrevious.Enabled = false;
116: }
117: else
118: {
119: objLbFirst.Enabled = true;
120: objLbPrevious.Enabled = true;
121: }
122:
123:
124: //Adding control in a place holder
125: plcPaging.Controls.Add(objLbFirst);
126: plcPaging.Controls.Add(new LiteralControl(" | ")); // Just to give some space
127: plcPaging.Controls.Add(objLbPrevious);
128: plcPaging.Controls.Add(new LiteralControl(" | "));
129:
130:
131: // Creatig page numbers based on the start and end limit variables.
132: for (int i = pageShowLimitStart; i <= pageShowLimitEnd; i++)
133: {
134: if ((Page.FindControl("lb_" + i.ToString()) == null) && i <= numberOfPages)
135: {
136: LinkButton objLb = new LinkButton();
137: objLb.Click += new EventHandler(objLb_Click);
138: objLb.Text = i.ToString();
139: objLb.ID = "lb_" + i.ToString();
140: objLb.CommandName = "pgChange";
141: objLb.EnableViewState = true;
142: objLb.CommandArgument = i.ToString();
143:
144: if ((currentPage + 1) == i)
145: {
146: objLb.Enabled = false;
147: }
148:
149:
150: plcPaging.Controls.Add(objLb);
151: plcPaging.Controls.Add(new LiteralControl(" | "));
152: }
153: }
154:
155: // Last Link button to display with paging
156: LinkButton objLbLast = new LinkButton();
157: objLbLast.Click += new EventHandler(objLb_Click);
158: objLbLast.Text = "Last";
159: objLbLast.ID = "lb_LastPage";
160: objLbLast.CommandName = "pgChange";
161: objLbLast.EnableViewState = true;
162: objLbLast.CommandArgument = numberOfPages.ToString();
163:
164: // Next Link button to display with paging
165: LinkButton objLbNext = new LinkButton();
166: objLbNext.Click += new EventHandler(objLb_Click);
167: objLbNext.Text = "Next";
168: objLbNext.ID = "lb_NextPage";
169: objLbNext.CommandName = "pgChange";
170: objLbNext.EnableViewState = true;
171: objLbNext.CommandArgument = (currentPage + 2).ToString();
172:
173: //of course if the page is the last page, then there is no need of last or next
174: if ((currentPage + 1) == numberOfPages)
175: {
176: objLbLast.Enabled = false;
177: objLbNext.Enabled = false;
178: }
179: else
180: {
181: objLbLast.Enabled = true;
182: objLbNext.Enabled = true;
183: }
184:
185:
186: // Adding Control to the place holder
187: plcPaging.Controls.Add(objLbNext);
188: plcPaging.Controls.Add(new LiteralControl(" | "));
189: plcPaging.Controls.Add(objLbLast);
190: plcPaging.Controls.Add(new LiteralControl(" | "));
191: }
192:
193: }
Yes, the code is complex that is why I wrote proper comments which will let you understand the stuff easily.
One last thing which is left, is the implementation of dynamically created link button onclick event.
1: void objLb_Click(object sender, EventArgs e)
2: {
3: plcPaging.Controls.Clear();
4: LinkButton objlb = (LinkButton)sender;
5: GridView1.PageIndex = (int.Parse(objlb.CommandArgument.ToString()) - 1);
6:
7: managePaging(dt);
8: }
There it is, we have now completed Custom Paging in Grid View. If you want to download the source code, here is the VS 2008 Solution.
Modification:
I have been receiving emails regarding the issues of this post. Especially with the initial five page numbers. I have modified this post to fix the bug it had. Please feel free to point further issues. Also, the download links are also modified.