DJ's Blog

David Jeavons' Blog at vbCity

This blog hosted by:
http://blogs.vbcity.com      
  Home :: Syndication  :: Login

JunJuly 2008Aug
SMTWTFS
293012345
6789101112
13141516171819
20212223242526
272829303112
3456789

Archives

Blogs I read

There are many times when you need to display a large amount of data to a user. When this need arises, you could of course use a DataGrid and make use of the in-built paging mechanism which makes paging a breeze. However, what if you can't use a DataGrid? Maybe the data you are displaying does not fit the structure of a DataGrid. Fortunately, we can borrow the DataGrid's paging mechanism and use it to create our own paging control which will allow us to add paging capabilities to a wider range of controls.

This post aims to give you an alternative that will allow you to create your own custom paging control which can be bound to any control that supports the IEnumerable Interface. Another goal of this control is to allow for the paging of any data that again supports the IEnumerable interface. So rather than only paging data from a Database (through the use of a DataTable or DataView), you can also bind an ArrayList for example to the paging control and page through the contents of the ArrayList or even create your own specialised class' that implements the IEnumerable interface and page through that.

Create the User Control

First, we need to create the user control, so add a new User Control item to your project and name it "Paging". Then add the following controls (you may want to add them to a table or div, the choice is yours):

Control TypeIDText
LinkButtonlkbMoveFirstMove First
LinkButtonlkbMovePreviousMove Previous
LabellblPageInformation 
LinkButtonlkbMoveNextMove Next
LinkButtonlkbMoveLastMove Last

Add the Paging Code

Copy the following code into the code-behind file of the Paging control:

Option Strict On

 

Partial Class paging

Inherits System.Web.UI.UserControl

 

'Member variables

Private _dataSource As IEnumerable

Private _pageSize As Int32 = 10

Private _pageNumber As Int32 = 0

Private _allowPaging As Boolean = True

Private _pageCount As Int32 = 0

 

Private pageSource As PagedDataSource 'Provides the paging functionality.

 

'An event that is raised each time the page is changed.

Public Event PageIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs)

 

Public Property DataSource() As IEnumerable

    Get

        Return _dataSource

    End Get

    Set(ByVal value As IEnumerable)

        _dataSource = value

    End Set

End Property

 

Public Property PageSize() As Int32

    Get

        Return _pageSize

    End Get

    Set(ByVal value As Int32)

        _pageSize = value

        'Store the _pageSize value in ViewState

        ViewState("PageSize") = _pageSize

    End Set

End Property

 

Public Property PageNumber() As Int32

    Get

        Return _pageNumber

    End Get

    Set(ByVal value As Int32)

        _pageNumber = value

        'Store the _pageNumber value in ViewState

        ViewState("PageNumber") = _pageNumber

    End Set

End Property

 

Public ReadOnly Property PageCount() As Int32

    Get

        Return _pageCount

    End Get

End Property

 

Public Property AllowPaging() As Boolean

    Get

        Return _allowPaging

    End Get

    Set(ByVal value As Boolean)

        _allowPaging = value

        'Store the _allowPaging value in ViewState

        ViewState("AllowPaging") = _allowPaging

    End Set

End Property

 

Private Sub Paging()

 

    'Create a new instance of the pageSource if required

    If pageSource Is Nothing Then pageSource = New PagedDataSource

 

    'Setup the pageSource

    With pageSource

 

        .DataSource = _dataSource

        .PageSize = _pageSize

        .AllowPaging = _allowPaging

 

        If _pageNumber > .PageCount Then

            Throw New ArgumentOutOfRangeException

        Else

            .CurrentPageIndex = _pageNumber

        End If

 

        'Display page information

        lblPageInformation.Text = "Page " & (.CurrentPageIndex + 1).ToString & " of " & .PageCount.ToString

 

        'Enable/Disable the navigation buttons based on where we are in the paging source.

        lkbMoveFirst.Enabled = Not .IsFirstPage

        lkbMovePrevious.Enabled = Not .IsFirstPage

        lkbMoveNext.Enabled = Not .IsLastPage

        lkbMoveLast.Enabled = Not .IsLastPage

 

        'Store the current page count in ViewState

        ViewState("PageCount") = .PageCount - 1

 

    End With

 

End Sub

 

Private Sub Navigation_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles _

 lkbMoveFirst.Click, lkbMovePrevious.Click, lkbMoveNext.Click, lkbMoveLast.Click

 

    'Retrieve instance data from ViewState if available

        If ViewState("PageSize") IsNot Nothing Then _pageSize = Int32.Parse(ViewState("PageSize").ToString)

        If ViewState("PageNumber") IsNot Nothing Then _pageNumber = Int32.Parse(ViewState("PageNumber").ToString)

        If ViewState("PageCount") IsNot Nothing Then _pageCount = Int32.Parse(ViewState("PageCount").ToString)

        If ViewState("AllowPaging") IsNot Nothing Then _allowPaging = Boolean.Parse(ViewState("AllowPaging").ToString)

 

                    'Determine which control initiated the Navigation_Click

                    Select Case CType(sender, LinkButton).ID.ToLower

                        Case "lkbmovefirst"

                            _pageNumber = 0

                        Case "lkbmoveprevious"

                            _pageNumber -= 1

                        Case "lkbmovenext"

                            _pageNumber += 1

                        Case "lkbmovelast"

                            _pageNumber = pageCount

                    End Select

 

                    'Update the ViewState values

                    ViewState("PageNumber") = _pageNumber

 

                    'Raise the PageIndexedChanged event

                    RaiseEvent PageIndexChanged(Me, Nothing)

 

End Sub

 

Public Function GetPage() As IEnumerable

 

    Paging()

    Return pageSource

 

End Function

 

End Class

Now to test the control.

Add a new web form and drop the paging control onto the page. You may need to wire up the paging control to your code-behind file using:

Protected WithEvents Paging1 As paging

This first test will show how you can page through data from a database using the Paging control and display that data in a ListBox. I have used the Northwind database in SQL Server for this example. Add the following code to your code-behind file:

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

 

    Dim connection As New System.Data.SqlClient.SqlConnection("Data Source=(local);Initial Catalog=Northwind;UID=xxx;Password=xxx")

    Dim adapter As New System.Data.SqlClient.SqlDataAdapter("SELECT * FROM Customers", connection)

    Dim dt As New System.Data.DataTable

 

    adapter.Fill(dt)

 

    'You can set your desired page size here or accept the default of 10 records.

    Me.Paging1.DataSource = dt.DefaultView

 

    ListBox1.Items.Clear()

 

    'Populate with first n items (n = page size)

    If Not Page.IsPostBack Then

 

        ListBox1.DataSource = Paging1.GetPage

        ListBox1.DataTextField = "ContactName"

        ListBox1.DataValueField = "CustomerID"

        ListBox1.DataBind()

 

    End If

 

End Sub

 

Protected Sub Paging1_PageIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles Paging1.PageIndexChanged

 

    ListBox1.DataSource = Paging1.GetPage

    ListBox1.DataTextField = "ContactName"

    ListBox1.DataValueField = "CustomerID"

    ListBox1.DataBind()

 

End Sub

In the above example, you will see that the DataSource of the paging control is set on Page Load and if the page is not a post back then the DataSource of the ListBox is set to the GetPage method of the paging control which returns the IEnumerable interface. Each time the page is changed, the PageIndexChanged event is raised and again, the DataSource of the ListBox is set to the GetPage method of the paging control.

The next example shows how you can perform the same paging but using an ArrayList instead of a DataTable. The same concept applies as in the first example:

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

 

    Dim myData As New ArrayList

 

    For i As Int32 = 1 To 100

        myData.Add(i)

    Next

 

    Paging1.DataSource = myData

 

    If Not Page.IsPostBack Then

 

        ListBox1.DataSource = Paging1.GetPage

        ListBox1.DataBind()

 

    End If

 

End Sub

 

Protected Sub Paging1_PageIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles Paging1.PageIndexChanged

 

    ListBox1.DataSource = Paging1.GetPage

    ListBox1.DataBind()

 

End Sub

In the above examples, the data has been bound to a ListBox, but as mentioned earlier, you can use the Paging control to bind to any control that supports the IEnumerable interface. Another thing to bear in mind is that you could also request an enumerator from the GetPage method and enumerate the page's data programatically without binding the Paging control to a web control. For example, if the Paging controls DataSource was set to a DataView then the following example, would enumerate through the current page data:

Dim myEnumerator As IEnumerator = Paging1.GetPage.GetEnumerator

Dim dv As Data.DataRowView = Nothing

 

Do While myEnumerator.MoveNext = True

 

    dv = CType(myEnumerator.Current, Data.DataRowView)

 

Loop

I hope this proves useful to somebody.

posted on Thursday, March 09, 2006 10:39 AM