In this article I will explain with an example, how to implement Paging using Skip and Take functions in LINQ in Windows Forms (WinForms) Application using C# and VB.Net.
 
 

Form Design

The following Form consists of:
DataGridView – For displaying data.
Panel – For adding pager buttons.
Paging using Skip and Take functions in LINQ using C# and VB.Net
 
 

Entity Framework Model

Once the Entity Framework is configured and connected to the database table, the Model will look as shown below.
Note: For beginners in Windows Forms and Entity Framework, please refer my article Entity Framework Database First Approach in Windows Forms using C# and VB.Net. It covers all the information needed for connecting and configuring Entity Framework.
 
Paging using Skip and Take functions in LINQ using C# and VB.Net
 
 

Property Class

The Class consists of following properties.
C#
public class Page
{
    public string Text { get; set; }
    public string Value { get; set; }
    public bool Selected { get; set; }
}
 
VB.Net
Public Class Page
    Public Property Text As String
    Public Property Value As String
    Public Property Selected As Boolean
End Class
 
 

Implementing Paging in DataGridView

First the value of the PageSize is set to 5.
Inside the Form Load event handler, the Name, HeaderText and DataPropertyName columns are set and the BindGrid method is called.

BindGrid

The BindGrid method accepts PageIndex as a parameter.
Inside the BindGrid method, the records are fetched from the Customers table of Northwind database using Entity Framework.
Then, a Generic List collection of Customer class object is created and LINQ query is executed.
The Paging is performed on the records using the Skip and Take functions.
 

Skip function

The Skip function accepts the Start Index from the set of records to fetched i.e. if Page Index is 1 then the Start Index will be (1 - 1) * 10 = 0.
Example: If Current Page Index is 1 and the Maximum Rows is 10, then the Start Index will be (1 - 1) * 10 = 0.
 

Take function

The Take function will fetch the rows based on the value of the PageSize variable.
 
The Generic List collection of Customer class object is assigned to the DataSource property of DataGridView.
Finally, the value of the RecordCount and PageIndex are passed to the PopulatePager method.
C#
int PageSize = 5;
private void Form1_Load(object  sender, EventArgs e)
{
    //Set AutoGenerateColumns False
    dgvCustomers.AutoGenerateColumns = false;
 
    //Set Columns Count
    dgvCustomers.ColumnCount = 3;
 
    //Add Columns
    dgvCustomers.Columns[0].Name = "CustomerID";
    dgvCustomers.Columns[0].HeaderText = "Customer Id";
    dgvCustomers.Columns[0].DataPropertyName = "CustomerID";
 
    dgvCustomers.Columns[1].HeaderText = "Contact Name";
    dgvCustomers.Columns[1].Name = "Name";
    dgvCustomers.Columns[1].DataPropertyName = "ContactName";
 
    dgvCustomers.Columns[2].Name = "Country";
    dgvCustomers.Columns[2].HeaderText = "Country";
    dgvCustomers.Columns[2].DataPropertyName = "Country";
 
    this.BindGrid(1);
}
 
public void BindGrid(int startIndex)
{
    using (NORTHWINDEntities entities = new NORTHWINDEntities())
    {
        List<Customer> customers = (from customer in entities.Customers
                                    select customer)
                                    .OrderBy(customer => customer.CustomerID)
                                    .Skip((startIndex - 1) * PageSize)
                                    .Take(PageSize).ToList();
        dgvCustomers.DataSource = customers;
        this.PopulatePager(entities.Customers.Count(), startIndex);
    }
}
 
VB.Net
Private PageSize As Integer = 5
Private Sub Form1_Load(ByVal sender As ObjectByVal e As EventArgs) Handles Me.Load
    'Set AutoGenerateColumns False
    dgvCustomers.AutoGenerateColumns = False
 
    'Set Columns Count
    dgvCustomers.ColumnCount = 3
 
    'Add Columns
    dgvCustomers.Columns(0).Name = "CustomerID"
    dgvCustomers.Columns(0).HeaderText = "Customer Id"
    dgvCustomers.Columns(0).DataPropertyName = "CustomerID"
 
    dgvCustomers.Columns(1).HeaderText = "Contact Name"
    dgvCustomers.Columns(1).Name = "Name"
    dgvCustomers.Columns(1).DataPropertyName = "ContactName"
 
    dgvCustomers.Columns(2).Name = "Country"
    dgvCustomers.Columns(2).HeaderText = "Country"
    dgvCustomers.Columns(2).DataPropertyName = "Country"
 
    Me.BindGrid(1)
End Sub
 
Public Sub BindGrid(ByVal startIndex As Integer)
    Using entities As NORTHWINDEntities = New NORTHWINDEntities()
        Dim customers As List(Of Customer) = (From customer In entities.Customers
                                                Select customer) _
                                                .OrderBy(Function(customer) customer.CustomerID) _
                                                .Skip((startIndex - 1) * PageSize) _
                                                .Take(PageSize).ToList()
        dgvCustomers.DataSource = customers
        Me.PopulatePager(entities.Customers.Count(), startIndex)
    End Using
End Sub
 
 

Populating the Pager

The PopulatePager method accepts the RecordCount and the current PageIndex.
Then, calculations are done to find the first and the last page of the pager and then a list of possible pages is generated by adding objects of the Page class to the Generic List collection.
Finally, a FOR EACH loop is executed over Page class present in the collection, its corresponding dynamic Button control is added to the Panel control.
Note: For more details about creating dynamic controls in Windows Applications, please refer my article Add Dynamic TextBox, Label and Button controls with TextChanged and Click event handlers in Windows Forms (WinForms) Application.
 
C#
private void PopulatePager(int recordCount, int currentPage)
{
    List<Page> pages = new List<Page>();
    int startIndex, endIndex;
    int pagerSpan = 5;
 
    //Calculate the Start and End Index of pages to be displayed.
    double dblPageCount = (double)((decimal)recordCount /Convert.ToDecimal(PageSize));
    int pageCount = (int)Math.Ceiling(dblPageCount);
    startIndex = currentPage > 1 && currentPage + pagerSpan - 1 < pagerSpan ? currentPage : 1;
    endIndex = pageCount > pagerSpan ? pagerSpan : pageCount;
    if (currentPage > pagerSpan % 2)
    {
        if (currentPage == 2)
        {
            endIndex = 5;
        }
        else
        {
             endIndex = currentPage + 2;
        }
    }
    else
    {
        endIndex = (pagerSpan - currentPage) + 1;
    }
 
    if (endIndex - (pagerSpan - 1) > startIndex)
    {
        startIndex = endIndex - (pagerSpan - 1);
    }
 
    if (endIndex > pageCount)
    {
        endIndex = pageCount;
        startIndex = ((endIndex - pagerSpan) + 1) > 0 ? (endIndex - pagerSpan) + 1 : 1;
    }
 
    //Add the First Page Button.
    if (currentPage > 1)
    {
        pages.Add(new Page { Text = "First", Value = "1" });
    }
 
    //Add the Previous Button.
    if (currentPage > 1)
    {
        pages.Add(new Page { Text = "<<", Value = (currentPage - 1).ToString() });
    }
 
    for (int i = startIndex; i <= endIndex; i++)
    {
        pages.Add(new Page { Text = i.ToString(), Value = i.ToString(), Selected = i == currentPage });
    }
 
    //Add the Next Button.
    if (currentPage < pageCount)
    {
        pages.Add(new Page { Text = ">>", Value = (currentPage + 1).ToString() });
    }
 
    //Add the Last Button.
    if (currentPage != pageCount)
    {
        pages.Add(new Page { Text = "Last", Value = pageCount.ToString() });
    }
 
    //Clear existing Pager Buttons.
    pnlPager.Controls.Clear();
 
    //Loop and add Buttons for Pager.
    int count = 0;
    foreach (Page page in pages)
    {
        Button btnPage = new Button();
        btnPage.Location = new System.Drawing.Point(38 * count, 5);
        btnPage.Size =  new System.Drawing.Size(35, 20);
        btnPage.Name = page.Value;
        btnPage.Text = page.Text;
        btnPage.Enabled = !page.Selected;
        btnPage.Click += new System.EventHandler(this.Page_Click);
        pnlPager.Controls.Add(btnPage);
        count++;
    }
}
 
VB.Net
Private Sub PopulatePager(ByVal recordCount As IntegerByVal currentPage As Integer)
    Dim pages As List(Of Page) =  New List(Of Page)()
    Dim startIndex, endIndex As Integer
    Dim pagerSpan As Integer = 5
 
    'Calculate the Start and End Index of pages to be displayed.
    Dim dblPageCount As Double = CDbl((CDec(recordCount) / Convert.ToDecimal(PageSize)))
    Dim pageCount As Integer = CInt(Math.Ceiling(dblPageCount))
     startIndex = If(currentPage > 1AndAlso currentPage + pagerSpan - 1 < pagerSpan, currentPage, 1)
     endIndex = If(pageCount > pagerSpan, pagerSpan, pageCount)
 
    If currentPage > pagerSpan Mod 2 Then
        If  currentPage = 2 Then
            endIndex = 5
        Else
            endIndex = currentPage + 2
        End If
    Else
        endIndex = (pagerSpan - currentPage) + 1
    End If
 
    If endIndex - (pagerSpan - 1) > startIndex Then
        startIndex = endIndex - (pagerSpan - 1)
    End If
 
    If endIndex > pageCount Then
        endIndex = pageCount
        startIndex =  If(((endIndex - pagerSpan) + 1) > 0, (endIndex - pagerSpan) + 1, 1)
    End If
 
    'Add the First Page Button.
    If currentPage > 1 Then
        pages.Add(New Page With {
             .Text = "First",
             .Value = "1"
        })
    End If
 
    'Add the Previous Button.
    If currentPage > 1 Then
        pages.Add(New Page With {
             .Text = "<<",
            .Value = (currentPage - 1).ToString()
        })
    End If
 
    For i As Integer = startIndex To endIndex
        pages.Add(New Page With {
            .Text = i.ToString(),
            .Value = i.ToString(),
            .Selected = i = currentPage
        })
    Next
 
    'Add the Next Button.
    If currentPage < pageCount Then
        pages.Add(New Page With {
             .Text = ">>",
            .Value = (currentPage + 1).ToString()
        })
    End If
 
    'Add the Last Button.
    If currentPage <> pageCount Then
        pages.Add(New Page With {
             .Text = "Last",
            .Value = pageCount.ToString()
        })
    End If
 
    'Clear existing Pager Buttons.
    pnlPager.Controls.Clear()
 
    'Loop and add Buttons for Pager.
    Dim count As Integer = 0
    For Each page As Page In pages
        Dim btnPage As Button = New Button()
        btnPage.Location = New System.Drawing.Point(38 * count, 5)
        btnPage.Size = New System.Drawing.Size(35, 20)
        btnPage.Name = page.Value
        btnPage.Text = page.Text
        btnPage.Enabled = Not page.Selected
        AddHandler btnPage.Click, New System.EventHandler(AddressOf Me.Page_Click)
        pnlPager.Controls.Add(btnPage)
        count += 1
    Next
End Sub
 
 

Page Click

Each dynamic Button is assigned to a click event handler, when the Button is clicked the BindGrid method is called.
And the value of its Name is passed as PageIndex parameter which populates the DataGridView with the new set of records.
C#
private void Page_Click(object sender, EventArgs e)
{
    Button btnPager = (sender as Button);
    this.BindGrid(int.Parse(btnPager.Name));
}
 
VB.Net
Private Sub Page_Click(ByVal sender As ObjectByVal e As EventArgs)
    Dim btnPager As Button = (TryCast(sender, Button))
    Me.BindGrid(Integer.Parse(btnPager.Name))
End Sub
 
 

Screenshot

Paging using Skip and Take functions in LINQ using C# and VB.Net
 
 

Downloads