How to implement custom paging on a WPF DataGrid?

In this post we are going to learn the pagination in the data grid where we will have options to select the number of records to be displayed per page in the data grid. you can select the count from the record per page combobox and based on that you can see the records.

I will add the four buttons which is used for show the first page, previous page, next page and last page.

Below is DataGrid control code:

 <DataGrid Grid.Row="1" ItemsSource="{Binding EmployeeCollection}" 

                  AutoGenerateColumns="False" CanUserAddRows="False">

            <DataGrid.Columns>

                <DataGridTextColumn Header="ID" Binding="{Binding ID}"/>

                <DataGridTextColumn Header="Name" Binding="{Binding Name}"/>

                <DataGridTextColumn Header="Age" Binding="{Binding Age}"/>

                <DataGridTextColumn Header="Gender" Binding="{Binding Gender}"/>

                <DataGridTextColumn Header="Address" Binding="{Binding Address}"/>

                <DataGridTemplateColumn Header="Action">

                    <DataGridTemplateColumn.CellTemplate>

                        <DataTemplate>

                            <StackPanel Orientation="Horizontal" Margin="4" >

                                <TextBox Text="{Binding Name}"/>

                                <Button Name="BtnUpdate" Content="Update"  Width="60" Height="25" Margin="10,0,0,0"

                                                Command="{Binding DataContext.UpdateCommand,RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"

                                                CommandParameter="{Binding}"/>


                                <Button Name="BtnDelete" Content="Delete"  Width="60" Height="25" Margin="10,0,0,0" 

                                                Command="{Binding DataContext.DeleteCommand,RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"

                                                CommandParameter="{Binding}"/>

                            </StackPanel>

                        </DataTemplate>

                    </DataGridTemplateColumn.CellTemplate>

                </DataGridTemplateColumn>

            </DataGrid.Columns>

        </DataGrid>

       

Below is pagination control code:

 <StackPanel Grid.Row="2" HorizontalAlignment="Right" Orientation="Horizontal">

            <TextBlock Text="Records per page" VerticalAlignment="Center" Margin="5"/>

            <ComboBox Margin="5"  Width="100" SelectedItem="{Binding SelectedRecord,UpdateSourceTrigger=PropertyChanged}">

                <sys:Int32>10</sys:Int32>

                <sys:Int32>15</sys:Int32>

                <sys:Int32>20</sys:Int32>

                <sys:Int32>25</sys:Int32>

            </ComboBox>

            <Button Content="&lt;&lt;" Width="40" IsEnabled="{Binding IsFirstEnabled}"

                    ToolTip="First page" Margin="5" Command="{Binding FirstCommand}"/>

            <Button Content="&lt;" Width="40" Margin="5" IsEnabled="{Binding IsPreviousEnabled}"

                    ToolTip="Previous page" Command="{Binding PreviousCommand}"/>

            <TextBlock VerticalAlignment="Center">

                <TextBlock.Text>

                    <MultiBinding StringFormat="{} {0} of {1}">

                        <Binding Path="CurrentPage"/>

                        <Binding Path="NumberOfPages"/>

                    </MultiBinding>

                </TextBlock.Text>

            </TextBlock>

            <Button Content=">" Width="40" Margin="5" IsEnabled="{Binding IsNextEnabled}" 

                    ToolTip="Next page"  Command="{Binding NextCommand}"/>

            <Button Content=">>" Width="40" Margin="5" IsEnabled="{Binding IsLastEnabled}"

                    ToolTip="Last page" Command="{Binding LastCommand}"/>

        </StackPanel>


If you observe in Button control i have used &lt; for "<" symbol because we can't use "<" symbol in xaml.


To the view model assign the all buttons command inside constructor like below:

          

            FirstCommand = new Command((s) => true, FirstPage);

            LastCommand = new Command((s) => true, LastPage);

            NextCommand = new Command((s) => true, NextPage);

            PreviousCommand = new Command((s) => true, PreviousPage); 


Now create all the four methods

 private void FirstPage(object obj)

        {

            UpdateCollection(LstOfRecords.Take(SelectedRecord));

            CurrentPage = 1;

            UpdateEnableState();

        }

 private void LastPage(object obj)

        {

            var recordsToskip = SelectedRecord * (NumberOfPages - 1);

            UpdateCollection(LstOfRecords.Skip(recordsToskip));

            CurrentPage = NumberOfPages;

            UpdateEnableState();

        }

        private void NextPage(object obj)

        {

            RecordStartFrom = CurrentPage * SelectedRecord;

            var recordsToShow = LstOfRecords.Skip(RecordStartFrom).Take(SelectedRecord);

            UpdateCollection(recordsToShow);

            CurrentPage++;

            UpdateEnableState();

        } 

private void PreviousPage(object obj)

        {

            CurrentPage--;

            RecordStartFrom = LstOfRecords.Count - SelectedRecord * (NumberOfPages - (CurrentPage - 1));

            var recorsToShow = LstOfRecords.Skip(RecordStartFrom).Take(SelectedRecord);

            UpdateCollection(recorsToShow);

            UpdateEnableState();

        }

I have used one variable RecordStartFrom inside methods so create on int type variable and assign it to 0

int RecordStartFrom = 0;

Also i have used properties in method so add all these property to viewmodel

private int _numberOfPages = 10;


        public int NumberOfPages

        {

            get { return _numberOfPages; }

            set

            {

                _numberOfPages = value;

                OnPropertyChanged(nameof(NumberOfPages));

                UpdateEnableState();

            }

        }

        private bool _isFirstEnabled;


        public bool IsFirstEnabled

        {

            get { return _isFirstEnabled; }

            set

            {

                _isFirstEnabled = value;

                OnPropertyChanged(nameof(IsFirstEnabled));

            }

        }

        private bool _isPreviousEnabled;


        public bool IsPreviousEnabled

        {

            get { return _isPreviousEnabled; }

            set

            {

                _isPreviousEnabled = value;

                OnPropertyChanged(nameof(IsPreviousEnabled));

            }

        }

        private bool _isNextEnabled;


        public bool IsNextEnabled

        {

            get { return _isNextEnabled; }

            set

            {

                _isNextEnabled = value;

                OnPropertyChanged(nameof(IsNextEnabled));

            }

        }

        private bool _isLastEnabled;


        public bool IsLastEnabled

        {

            get { return _isLastEnabled; }

            set

            {

                _isLastEnabled = value;

                OnPropertyChanged(nameof(IsLastEnabled));

            }

        }


 private int _selectedRecord = 10;


        public int SelectedRecord

        {

            get { return _selectedRecord; }

            set

            {

                _selectedRecord = value;

                OnPropertyChanged(nameof(CurrentPage));

                UpdateRecordCount();

            }

        }


 private int _currentPage = 1;


        public int CurrentPage

        {

            get { return _currentPage; }

            set

            {

                _currentPage = value;

                OnPropertyChanged(nameof(CurrentPage));

                UpdateEnableState();

            }

        }


Now i will define the method UpdateCollection which will updated our binded collection to show the correct items to the DataGrid.

private void UpdateCollection(IEnumerable<EmployeeDetail> enumerable)
        {
            LstEmployeeDetail.Clear();
            foreach (var item in enumerable)
            {
                LstEmployeeDetail.Add(item);
            }
        }

Now i will define the method UpdateEnableState which will update the Button state like if Button should enable or disable.

       private void UpdateEnableState()

        {

            IsFirstEnabled = CurrentPage > 1;

            IsPreviousEnabled = CurrentPage > 1;

            IsNextEnabled = CurrentPage < NumberOfPages;

            IsLastEnabled = CurrentPage < NumberOfPages;

        }

Now i will define the method UpdateRecordCount which will update the NumberOfPages and CurrentPage properties and also will update the collection on the Records per page  selection change.

private void UpdateRecordCount()

        {

            NumberOfPages = (int)Math.Ceiling((double)LstOfRecords.Count / SelectedRecord);

            NumberOfPages = NumberOfPages == 0 ? 1 : NumberOfPages;

            UpdateCollection(LstOfRecords.Take(SelectedRecord));

            CurrentPage = 1;

        }

       

                                                                                                            Happy Coding!!!

Comments

Popular posts from this blog

Pagination of DataGrid in WPF using MVVM

Connect SQL Server Database to WPF Application and Perform CRUD Operations

Filter DataGrid and ListView in wpf using ICollectionView