Paginating DataGridView using BindingNavigator and BindingSource

In this lesson we will learn how to perform pagination to our datagridview data. Those data are retrieved from MS Access database. Note that this lesson is part of the course series we are currently covering: C# Contacts Management System development course. In the course we are developing a full Contacts Management System using C#. That system will be powered by Microsoft Access database.

To do the pagination, the following classes will be important:

  1. BindingSource - To represent our data source. The data that needs to be paged.
  2. BindingNavigator - To give us our pagination controls.
  3. DataGridView - Our data rendering component.

Why Paginate Data?

Data Pagination is important as it allows us view or load data in chunks. When loading data, this gives a performance advantage since you load only a small amount of data at a time. This consumes less memory and is faster to load.

When rendering data as we are, it offers a better way of viewing or analysing data. Instead of viewing 100 rows at a time, it is easier to view 10 records at a time and move to other pages as we wish. This is what we are using pagination for.

What You Will Learn in This lesson.

  1. How to paginate or page data.
  2. How to bind paged data to a datagridview.
  3. How to use BindingNavigator and BindingSource to paginate data.

NOTE: To get the most from this lesson you may need to view the other lessons course.

Step 1: Create Class,Add imports

First create a file called Paginator in a file Paginator.cs. I have placed mine in a foder called Common: /Common/Paginator.cs.

Then first add using statements:

using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows.Forms;
using ContactManager.Data.Model;

Then create our namespace as well as class:

namespace ContactManager.Common
{
    class Paginator
    {
        ....

Then we define several instance as well as class fields:

        private readonly BindingSource bindingSource1;
        private BindingNavigator bindingNavigator1;
        private readonly DataGridView dataGridView1;
        private static List<Contact> contacts;
        private const int pageSize = 8;
        private static int numTotalItems;

In the above we have defined:

  1. BindingSource - To represent our data source.
  2. BindingNavigator - To represent our navigation controls.
  3. DataGridView - To represent our data rendering form.
  4. List - our generic list of contacts. This list will hold the list of contacts that we intend to paginate.
  5. pageSize - the number of items to be shown in a single page.
  6. numTotalItems - the total number of items that we want to page.

Step 2 : Create PageOffset

Create an inner class called PageOffsetList. Make it extend the IListSource.

        private class PageOffsetList : IListSource
        {

We've created above class, and it's a custom collection class.The important part is that we've made it implement the IListSource interface. Doing that will make the class above class boundable/bindable to a data source.

Then we will implement two methods.

The first:

 public bool ContainsListCollection { get; protected set; }

The above method returns a boolean indicating whether the collection is a collection of System.Generic.IList objects.

Then the second method:

            public IList GetList()
            {
                // Return a list of page offsets based on "numTotalItems" and "pageSize"
                numTotalItems = contacts.Count;
                var pageOffsets = new List<int>();
                for (int currentItemIndex = 0; currentItemIndex < numTotalItems;
                 currentItemIndex += pageSize)
                    pageOffsets.Add(currentItemIndex);
                return pageOffsets;
            }
        }

Then outside the PageOffsetList class, we create our constructor:

        public Paginator(BindingSource mBindingSource,BindingNavigator mBindingNavigator,
        DataGridView mDataGridView,List<Contact> mContacts )
        {
            this.bindingSource1 = mBindingSource;
            this.bindingNavigator1 = mBindingNavigator;
            this.dataGridView1 = mDataGridView;
            Paginator.contacts = mContacts;
            bindingNavigator1.BindingSource = bindingSource1;
            bindingSource1.CurrentChanged += bindingSource1_CurrentChanged;
            bindingSource1.DataSource = new PageOffsetList();
        }

As you can see we are passing the following intor our Paginator contructor:

  1. BindingSource object.
  2. BindingNavigator object.
  3. DataGridView object.
  4. List of contacts.

Then lastly:

        private void bindingSource1_CurrentChanged(object sender, EventArgs e)
        {
            // The desired page has changed, so fetch the page of records using the
            //"Current" offset
            int currentPageOffset = (int) bindingSource1.Current;
            var records = new List<Contact>();
            for (int i = currentPageOffset; i < currentPageOffset + pageSize && i < contacts.Count;
             i++)
                records.Add(contacts[i]);

            dataGridView1.DataSource = records;
        }
    }
}
//end

We are creating our event handler for the BindingSource object's CurrentChanged event.

FULL CODE

/Common/Paginator.cs

Here is the full code:

using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows.Forms;
using ContactManager.Data.Model;

namespace ContactManager.Common
{
    class Paginator
    {
        private readonly BindingSource bindingSource1;
        private BindingNavigator bindingNavigator1;
        private readonly DataGridView dataGridView1;
        private static List<Contact> contacts;
        private const int pageSize = 8;
        private static int numTotalItems;

        /*
         * We start by creating a private class implementing the IListSource.
         * IListSource is an interface that allows it's implementer to return a
         list that can be bound to a data source.
         */
        private class PageOffsetList : IListSource
        {
            //We will implement two methods of the IListSource:
            //ContainsCollection returns a boolean value indicating whether the
            //collection is a collection of System.Collections.IList
            //     objects
            public bool ContainsListCollection { get; protected set; }

            //GetList() Returns a System.Collections.IList that can be bound to a
             //data source from
            //     an object that does not implement an System.Collections.IList itself.
            public IList GetList()
            {
                // Return a list of page offsets based on "numTotalItems" and "pageSize"
                numTotalItems = contacts.Count;
                var pageOffsets = new List<int>();
                for (int currentItemIndex = 0; currentItemIndex < numTotalItems;
                 currentItemIndex += pageSize)
                    pageOffsets.Add(currentItemIndex);
                return pageOffsets;
            }
        }
        /**
         * Our constructor will take several parameters including:
         * 1. BindingSource - Represents the data source of our form
         * 2. BindingNavigator - Represents the pagination and navigation controls we use
          to navigate.
         * 3. DataGridView - Our data rendering component.
         * 4. List<T> - The collection that should be paged
         *
         */
        public Paginator(BindingSource mBindingSource,BindingNavigator mBindingNavigator,
        DataGridView mDataGridView,List<Contact> mContacts )
        {
            this.bindingSource1 = mBindingSource;
            this.bindingNavigator1 = mBindingNavigator;
            this.dataGridView1 = mDataGridView;
            Paginator.contacts = mContacts;
            bindingNavigator1.BindingSource = bindingSource1;
            bindingSource1.CurrentChanged += bindingSource1_CurrentChanged;
            bindingSource1.DataSource = new PageOffsetList();
        }

        private void bindingSource1_CurrentChanged(object sender, EventArgs e)
        {
            // The desired page has changed, so fetch the page of records using the
            //"Current" offset
            int currentPageOffset = (int) bindingSource1.Current;
            var records = new List<Contact>();
            for (int i = currentPageOffset; i < currentPageOffset + pageSize && i < contacts.Count;
             i++)
                records.Add(contacts[i]);

            dataGridView1.DataSource = records;
        }
    }
}
//end

Now move over to the next lesson in this course.

Related Posts

Leave a Reply

Your email address will not be published. Required fields are marked *