Introduction
While working on a project, I realized the need to use the DataList control to present my content data in a list of records format. However the problem encountered while dealing with large number of data records, the user has to wait until all the data is retrieved from the database and bound to the DataList. Of course I could have used the DataGrid control because it already implements inbuilt paging, however I did not require all the other features that it supports other then that, I also wanted to have some control over the displayed HTML and therefore it was time to build my own paging mechanism with the DataList control.
I am sure that you are familiar with the DataList control, if not I recommend you to check the below link for more information.
http://www.w3schools.com/aspnet/aspnet_datalist.asp
Here are the steps that we will perform throughout this demonstration.
- Create a user control and the specified UI
- Write the server side code to implement the needed functionality
HTML Code
In the user control, we will create two panels which will serve as containers for the DataList and the navigation toolbar. The below code shows the HTML for our containers.
<asp:panel id="DataListContainer"
style="Z-INDEX: 101; LEFT: 6px; POSITION: absolute; TOP: 60px"
Runat="server"
width="100%">
<asp:DataList id="DataList1"
BorderWidth="1px"
GridLines="Both"
BorderStyle="None"
BorderColor="#3366CC"
Width="100%" runat="server">
<%-- Style tags ommited to display HTML--%>
<ItemTemplate>
<b><u>FirstName</u></b>
<asp:Label ID="lblName" Runat="server">
<%#DataBinder.Eval(Container.DataItem,"FirstName")%>
</asp:Label><br />
<b><u>LastName</u></b>
<asp:Label ID="lblLastName" Runat="server">
<%#DataBinder.Eval(Container.DataItem,"LastName")%>
</asp:Label><br />
<b><u>Company</u></b>
<asp:Label ID="lblCompany" Runat="server">
<%#DataBinder.Eval(Container.DataItem,"Company")%>
</asp:Label>
<div id="Line" runat="server"
style="azimuth:center; text-align:center;">
<hr style="width:50%;azimuth:center" />
</div>
</ItemTemplate>
<HeaderStyle Font-Bold="True"
ForeColor="#CCCCFF"
BackColor="#003399" />
</asp:DataList>
<asp:panel id="Navigation" style="TEXT-ALIGN: center" Width="100%"
runat="server" Height="17">
<table>
<tr>
<td style="WIDTH: 400px; TEXT-ALIGN: left">
<asp:Label id="RecordNumber" runat="server"
CssClass="RecordNumber"></asp:Label></td>
<td style="WIDTH: 200px; TEXT-ALIGN: left">
<asp:Label id="PageNumber" runat="server"
CssClass="RecordNumber"></asp:Label></td>
<td style="WIDTH: 50px; TEXT-ALIGN: left">
<asp:Label id="lblNext" runat="server"></asp:Label></td>
<td style="WIDTH: 50px; TEXT-ALIGN: left">
<asp:Label id="lblPrevious" runat="server"></asp:Label></td>
<td style="FLOAT: right; WIDTH: 25px; CURSOR: hand">
<asp:ImageButton id="Previous" Runat="server"
AlternateText="Previous page"
ImageUrl="Resources/NewsImages/Navigation/Back.jpg" /></td>
<td style="FLOAT: left; WIDTH: 25px; CURSOR: hand">
<asp:ImageButton id="Next" style="POSITION: relative" Width="16"
runat="server" AlternateText="Next Page"
ImageUrl="Resources/NewsImages/Navigation/Next.jpg" /></td>
</tr>
</table>
</asp:panel>
</asp:panel>
Two images have been used (Next and Previous) which can be found in the attached download zip file.
Code Behind
In this section, we will write the necessary code to implement our logic. First we will setup the database connection, retrieve our data, filter them based on specific criteria, and then bind it to the control.
Below are the main events and methods we will use:
- The
page_load event used to open a database connection, fill the DataSet which will be saved into a session variable to increase the performance and minimize the need for an opened connection while users are navigating through the control.
- We will handle two
onclick events for the next and previous ImageButtons. The events are called GoNext and GoPrevious.
- The following helper functions are created:
BindDatalist, FillDataSet, BindAndSetPage, and SetNext/.
- A public string property
RowsNumber in which we will allow the developer to specify how many records to display per page.
The Page Load Event:
private void Page_Load(object sender, System.EventArgs e)
{
DataSet ds = Session["ds"] as DataSet;
if (ds == null)
{
// Save the dataset into a session variable
Session["ds"] = this.FillDataSet(ds);
// call the BindDataList function
BindDataList();
}
// Show the total number of records
RecordNumber.Text = "Total Number of News: " +
ds.Tables[0].Rows.Count.ToString();
}
In the code above, we will check if the session variable containing the DataSet is null, we will open the database connection, fetch our data and store them in a DataSet object through the FillDataSet function which will be saved into a session variable, and then call the BindDataList function.
FillDataSet Function
protected DataSet FillDataSet(DataSet ds)
{
// Get the connection string form the Web.Config file
string conString =
ConfigurationSettings.AppSettings["LocalSqlServer"].ToString();
// Set the select statement
string Select = "SELECT * FROM Customers";
// Create an instance of the SqlDataAdapter object and fill the dataset
SqlDataAdapter da = new SqlDataAdapter(Select, conString);
// Fill the dataset
da.Fill(ds, "Customers");
return ds;
}
FillDataSet Method
protected void BindDataList()
{
this.SetObjects();
// Check if the number of rows per page is specified
if(rowsNumber != null || rowsNumber != string.Empty)
{
// store the number of rows per page in an integer variable
int rowsToDisplay = Convert.ToInt32(rowsNumber);
if(rowsToDisplay >0 && rowsToDisplay < dt.Rows.Count)
{
// if page is first time loaded
if (!Page.IsPostBack)
{
// Filter the dataview according to the first two records
dv.RowFilter = "ID >= 1 AND ID<= " +
dt.Rows[Convert.ToInt32(rowsNumber)-1]["ID"];
// get the number of Pages
double pageNumber = Convert.ToDouble(dt.Rows.Count) / rowsToDisplay;
int pageNumb = Convert.ToInt32(Math.Ceiling(pageNumber));
Session["PageNumber"] = pageNumb;
// Display The current page and the max number of pages.
PageNumber.Text = "Page 1 of " + pageNumb.ToString();
// if more than 1 page and the specified rows
are less than the records number
if (pageNumb > 1 && rowsToDisplay < dt.Rows.Count)
{
// Set the ID of the next two records to be displayed inside a label
this.SetNext(rowsToDisplay,0);
}
else
{
// Hide the Previous and Next images
Page.RegisterStartupScript("hideimage","<script language=javascript>
document.getElementById('Back').style.display='none';
document.getElementById('Next').style.display='none';
</script>");
}
}
else
{
// Set the next records ids
this.SetNext(rowsToDisplay,0);
}
}
else
{
// Hide the Previous and Next images
Page.RegisterStartupScript("hideimage","<script language=javascript>
document.getElementById('"+Next.ClientID+"').style.display='none';
document.getElementById('"+Previous.ClientID+"').style.display='none';
</script>");
}
this.BindAndSetPage(true,true);
}
}
The code above is responsible for filtering data to show specified records in the DataList control. We used the DataView object to filter records based on the ID column in the database, Calculated the number of pages, then calling the SetNext method which is used to retrieve the next two ids to be saved inside a hidden Label control. Of course, the JavaScript code is injected to the form to show or hide the images; finally we bind the DataList to the DataView object.
protected void SetObjects()
{
// retrieve the dataset from the session and create a Dataview object
DataSet ds = (DataSet)Session["ds"];
dt = ds.Tables[0];
dv = dt.DefaultView;
}
BindAndSetPage Function
protected void BindAndSetPage(bool IsNext,bool firstLoad)
{
int pagesNumb = Convert.ToInt32(Session["PageNumber"]);
string[] pageNumb = PageNumber.Text.Split(' ');
if(!firstLoad)
{
if(!IsNext)
{
// set the page number
int pages = Convert.ToInt32(pageNumb[1])-1;
PageNumber.Text = "Page " + pages.ToString() + " of " +
pagesNumb.ToString();
}
else
{
int pages = Convert.ToInt32(pageNumb[1])+ 1;
PageNumber.Text = "Page " + pages.ToString() + " of " +
pagesNumb.ToString();
}
}
// Bind the datasource
DataList1.DataSource = dv;
DataList1.DataBind();
Page.DataBind();
}
Figure 1

You should see a similar screenshot as above, when the datalist control is first loaded.
SetNext Function
protected void SetNext(int rowsToDisplay,int finalRecord)
{
if(!Page.IsPostBack)
{
Page.RegisterStartupScript("hideimage", "<script language=javascript>
document.getElementById('"+Previous.ClientID+"').style.display='none';
</script>");
}
if(finalRecord>-1)
{
// Cleat the next label
lblNext.Text = "";
// Get the number of records
int rowsCount = dt.Rows.Count;
int nextRows = finalRecord + rowsToDisplay;
if(rowsCount -1 > nextRows)
{
// set the next label to the next records
lblNext.Text = nextRows.ToString() + " " + (nextRows +1).ToString();
}
else
{
// save the next first record in a variable
string nextText = Convert.ToString(finalRecord + rowsToDisplay-1);
if(Convert.ToInt32(nextText) < rowsCount -1)
{
// get the id of the next first record
lblNext.Text = dt.Rows[Convert.ToInt32(nextText)]["ID"].ToString();
// loop through all the next records
for(int i= finalRecord + rowsToDisplay; i<rowsCount -1;i++)
{
// save the records ID in the next label
lblNext.Text = lblNext.Text + " " + dt.Rows[i]["ID"];
if(i == rowsCount)
{
// Hide the next image
Page.RegisterStartupScript("hideimage", "<script language=javascript>
document.getElementById('"+Next.ClientID+"').style.display='none';
</script>");
}
}
}
else
{
// hide the next image
Page.RegisterStartupScript("hideimage", "<script language=javascript>
document.getElementById('"+Next.ClientID+"').style.display='none';
</script>");
}
}
}
}
The above method is used to save the next records ID into a label control.
The values are then used each time the user presses the Next or Previous link to keep track
on which records to display on each event.
GoNext Event
protected void GoNext(object sender, System.Web.UI.ImageClickEventArgs e)
{
// Get the number of records
int rowsToDisplay = Convert.ToInt32(rowsNumber);
// Get the next id from the hidden label
string next = lblNext.Text;
// Get the dataset from the session and create a DataView object
DataSet ds = (DataSet)Session["ds"];
DataView dt = new DataView(ds.Tables[0]);
// if more than 2 records id exists
if(next.Length >1)
{
// Split the hidden label text by the space character
string[] records = next.Split(Convert.ToChar(" "));
// filter the DataView
dt.RowFilter = "ID >= " + records[0] + " AND ID <= " + records[1];
// Get the previous ID
int previousID = Convert.ToInt32(records[0]) - rowsToDisplay;
// Save the previous Two records ID in the hidden previous label
lblPrevious.Text = previousID.ToString() + " " +
(Convert.ToInt32(records[0]) -1).ToString();
// set the next records ID
int finalRecord = Convert.ToInt32(records[0]);
this.SetNext(ds,rowsToDisplay,finalRecord);
}
else
{
if(next != string.Empty)
{
dt.RowFilter = "ID = " + next;
Page.RegisterStartupScript("hideimage", "<script language=javascript>
document.getElementById('"+Next.ClientID+"').style.display='none';
</script>");
// Set the previous id
int previousID = Convert.ToInt32(next) - rowsToDisplay ;
lblPrevious.Text = previousID.ToString() + " " +
(Convert.ToInt32(next) -1).ToString();
}
}
// Set the Page Number
int pagesNumb = Convert.ToInt32(Session["PageNumber"]);
string[] pageNumb = PageNumber.Text.Split(' ');
int pages = Convert.ToInt32(pageNumb[1])+ 1;
PageNumber.Text = "Page " + pages.ToString() + " of " + pagesNumb.ToString();
// Bind the dataView to the datalist
DataList1.DataSource = dt;
DataList1.DataBind();
Page.DataBind();
}
The GoNext event is used to handle the Next image click event. In the above code, we will retrieve the values from the label control, filter the DataView object based on these values, set the previous and next records id and then bind it to the DataList control.
GoPrevious Event
protected void GoPrevious(object sender, System.Web.UI.ImageClickEventArgs e)
{
// Save the next records into a variable and get the total number of rows.
string next = lblNext.Text;
int rowsToDisplay = Convert.ToInt32(rowsNumber);
this.SetObjects();
// get the previous id from the hidden label
string previousID = lblPrevious.Text;
string[] filterPreID = previousID.Split(Convert.ToChar(" "));
//set the next two recrods
this.SetNext(rowsToDisplay,Convert.ToInt32(filterPreID[0]));
// set the previous id in the hidden label
int lastprevID = Convert.ToInt32(filterPreID[0]);
if((lastprevID - rowsToDisplay) > -1)
{
lblPrevious.Text = Convert.ToString((lastprevID - rowsToDisplay)) + " " +
Convert.ToString((lastprevID -1));
}
else
{
Page.RegisterStartupScript("hideimage", "<script language=javascript>
document.getElementById('"+Previous.ClientID+"').style.display='none';
</script>");
}
// filter the dataview
dv.RowFilter= "ID >= " + dt.Rows[lastprevID]["ID"] + " AND ID<= " +
dt.Rows[Convert.ToInt32(filterPreID[1])]["ID"] ;
this.BindAndSetPage(false,false);
}
The above code is being executed when the previous image is clicked. It is similar to the GoNext functionality however to retrieve previous records.
We are retrieving the values of the previous records from a hidden label.
Figure 2

The above figure will show how the DataList control will look when the user clicked on the next image.
You may have realized that the next image now is hidden because there are no records to navigate.
The RowsNumber Property
public string RowsNumber
{
get
{
return rowsNumber;
}
set
{
rowsNumber = value;
}
}
The above property is used to enable the developer to specify how many records he/she wants to display per page.
The main advantage of this user control is to give the developer the option to specify how many
records he/she wants to display per page. This can be achieved by setting the RowsNumber property.
<uc1:PagingDataList
id="PagingDataList1"
runat="server"
rowsNumber="25"/>
Conclusion
After completing the demonstration, you will have a better understanding on how to implement custom paging with a DataList control. It has been developed as a user control to include it into future projects. The page and injected JavaScript files has been tested on IE7 and Mozilla Firefox 2.0.
Download
Paging Project
About Haissam Abdul Malak
 |
Haissam Abdul Malak works as software developer in CCC. He has been developing web application using ASP.NET technology over the last 3 years. He achieved the Microsoft Certified Application Developer [MCAD] and been certified since 2006.
He is a regular contributor on the ASP.NET official forums (...
View complete profile
|
Top Articles in this category
JavaScript with ASP.NET 2.0 Pages - Part 1
ASP.NET 2.0 has made quite a few enhancements over ASP.NET 1.x in terms of handling common client-side tasks. It has also created new classes, properties and method of working with JavaScript code. This article explores the enhancements and the various ways of injecting JavaScript programmatically into ASP.NET 2.0 pages.
ASP.NET ComboBox
The ASP.NET ComboBox is an attempt to try and enhance some of the features of the Normal ASP.NET DropDownList.
Upload multiple files using the HtmlInputFile control
In this article, Haissam Abdul Malak will explain how to upload multiple files using several file upload controls. This article will demonstrates how to create a webform with three HtmlInputFile controls which will allow the user to upload three files at a time.
JavaScript with ASP.NET 2.0 Pages - Part 2
ASP.NET provides a number of ways of working with client-side script. This article explores the usage and drawbacks of ASP.NET script callbacks, and briefly presents a bird's view of ASP.NET AJAX.
Using WebParts in ASP.Net 2.0
This article describes various aspects of using webparts in asp.net 2.0.
|
|
Please login to rate or to leave a comment.