我们如何在winform的datagridview中进行分页

Posted

技术标签:

【中文标题】我们如何在winform的datagridview中进行分页【英文标题】:How can we do pagination in datagridview in winform 【发布时间】:2011-02-19 00:37:20 【问题描述】:

我想在窗口窗体的 datagridview 中每页显示 10 条记录,用户必须单击下一步按钮才能显示接下来的 10 条记录。 DataGridview 中是否有一些属性或者我需要创建一个自定义控件。

我需要做些什么来实现这一目标。

【问题讨论】:

这个链接可能对programcall.com/9/dotnet/…有帮助 【参考方案1】:

这是一个简单的工作示例,其中 BindingNavigator GUI 控件使用一个 BindingSource 对象 通过将其 DataSource 设置为 IListSource 的自定义子类来识别分页符。 (感谢this answer 关键思想。)当用户单击“下一页”按钮时,BindingNavigator 会触发bindingSource1_CurrentChanged,您的代码可以获取所需的记录。说明:

    创建 Windows 窗体应用程序 将 BindingNavigator、DataGridView 和 BindingSource 拖到窗体上 将 Form1.cs 替换为以下代码:
using System;
using System.Collections.Generic;
using System.Windows.Forms;

namespace PagedDataGridView

    public partial class Form1 : Form
    
        private const int totalRecords = 43;
        private const int pageSize = 10;

        public Form1()
        
            InitializeComponent();
            dataGridView1.Columns.Add(new DataGridViewTextBoxColumn  DataPropertyName = "Index" );
            bindingNavigator1.BindingSource = bindingSource1;
            bindingSource1.CurrentChanged += new System.EventHandler(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 offset = (int)bindingSource1.Current;
            var records = new List<Record>();
            for (int i = offset; i < offset + pageSize && i < totalRecords; i++)
                records.Add(new Record  Index = i );
            dataGridView1.DataSource = records;
        

        class Record
        
            public int Index  get; set; 
        

        class PageOffsetList : System.ComponentModel.IListSource
        
            public bool ContainsListCollection  get; protected set; 

            public System.Collections.IList GetList()
            
                // Return a list of page offsets based on "totalRecords" and "pageSize"
                var pageOffsets = new List<int>();
                for (int offset = 0; offset < totalRecords; offset += pageSize)
                    pageOffsets.Add(offset);
                return pageOffsets;
            
        
    

【讨论】:

@Rick Mohr:嗨!非常感谢你的代码。这真的很有帮助。只有一个问题。我有这样的代码: var transactionLogCount = TransactionLogManager.GetTransactionLogCount();上面的命令给出了总计数。 var transactionLogList = new List(); transactionLogList.AddRange(TransactionLogManager.GetAllTransactionLog(int StartIndex, int EndIndex); 现在当我需要在for循环中添加所有时间时如何进行分页。【参考方案2】:

这是我的解决方案:我花了将近一年的时间才找到它并为此感到自豪

public class SuperGrid : DataGridView
    
        public int PageSize
        
            get
            
                return _pageSize;
            
            set
            
                _pageSize = value;
            
        
        public int _pageSize = 10;
        BindingSource bs = new BindingSource();
        BindingList<DataTable> tables = new BindingList<DataTable>();
        public void SetPagedDataSource(DataTable dataTable, BindingNavigator bnav)
        
            DataTable dt = null;
            int counter = 1;
            foreach (DataRow dr in dataTable.Rows)
            
                if (counter == 1)
                
                    dt = dataTable.Clone();
                    tables.Add(dt);
                
                dt.Rows.Add(dr.ItemArray);
                if (PageSize < ++counter  )
                
                    counter = 1;
                
            
            bnav.BindingSource = bs;
            bs.DataSource = tables;
            bs.PositionChanged += bs_PositionChanged;
            bs_PositionChanged(bs, EventArgs.Empty);
        
        void bs_PositionChanged(object sender, EventArgs e)
        
            this.DataSource = tables[bs.Position];
        
    

如何使用它?将上面的代码添加到您的项目中,将 Supergrid 和 bindingnavigator 控件拖到您的 win 表单中。

 superGrid1.PageSize = 5;
 DataTable dt = DataProvider.ExecuteDt("select * from test order by col");
  superGrid1.SetPagedDataSource(dt, bindingNavigator1);

然后您就可以轻松获得一个带有数据绑定的分页 Datagridview/

【讨论】:

太棒了!刚刚创建了一个自定义控件以多次使用它。你应该改变几件事。 1.- 在 SetPagedDataSource 的开头你应该初始化变量 bs 和表: bs = new BindingSource();表 = 新的 BindingList(); 2.- 在 bs_PositionChanged() 中的操作之前检查 (bs.Position > 0)。恭喜! 如何修改列,假设要添加查看、编辑和删除等列【参考方案3】:

使用 C# 和 VB.Net 在 Windows 窗体 (WinForms) 应用程序中实现分页 DataGridView,这是另一种解决方案: https://www.aspsnippets.com/Articles/Implement-Paging-DataGridView-in-Windows-Forms-WinForms-Application-using-C-and-VBNet.aspx

本文将解释如何使用 C# 和 VB.Net 在 Windows 窗体 (WinForms) 应用程序中实现分页 DataGridView。 Windows 窗体 (WinForms) 应用程序中的 DataGridView 控件没有分页功能,因此需要实现使用存储过程的自定义分页。 存储过程接受 PageIndex 和 PageSize 作为输入参数,以便获取所需页面索引的记录。为了在前端填充 Pager,需要使用 RecordCount 输出参数获取表中的记录总数。

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
CREATE PROCEDURE [dbo].[GetCustomersPageWise]
      @PageIndex INT = 1
      ,@PageSize INT = 10
      ,@RecordCount INT OUTPUT
AS
BEGIN
      SET NOCOUNT ON;
      SELECT ROW_NUMBER() OVER
      (
            ORDER BY [CustomerID] ASC
      )AS RowNumber
            ,[CustomerID]
            ,[ContactName]
            ,[Country]
       INTO #Results
      FROM [Customers]

      SELECT @RecordCount = COUNT(*)
      FROM #Results

      SELECT [CustomerID]
            ,[ContactName]
            ,[Country] 
      FROM #Results
      WHERE RowNumber BETWEEN(@PageIndex -1) * @PageSize + 1 AND(((@PageIndex -1) * @PageSize + 1) + @PageSize) - 1

      DROP TABLE #Results
END

一开始,PageSize 的值设置为 5,PageIndex 设置为 1。RecordCount 输出参数和 PageIndex 的值被传递给 PopulatePager 方法(稍后讨论)。

C#
//Set the Page Size.
int PageSize = 5;
private void Form1_Load(object sender, EventArgs e)

    this.BindGrid(1);


private void BindGrid(int pageIndex)

    string constring = @"Data Source=.\SQL2005;Initial Catalog=Northwind;Integrated Security=true";
    using (SqlConnection con = new SqlConnection(constring))
    
        using (SqlCommand cmd = new SqlCommand("GetCustomersPageWise", con))
        
            cmd.CommandType = CommandType.StoredProcedure;
            cmd.Parameters.AddWithValue("@PageIndex", pageIndex);
            cmd.Parameters.AddWithValue("@PageSize", PageSize);
            cmd.Parameters.Add("@RecordCount", SqlDbType.Int, 4);
            cmd.Parameters["@RecordCount"].Direction = ParameterDirection.Output;
            con.Open();
            DataTable dt = new DataTable();
            dt.Load(cmd.ExecuteReader());
            dataGridView1.DataSource = dt;
            con.Close();
            int recordCount = Convert.ToInt32(cmd.Parameters["@RecordCount"].Value);
            this.PopulatePager(recordCount, pageIndex);
        
    

每个动态按钮都分配有一个单击事件处理程序,当单击按钮时,其名称的值作为 PageIndex 参数传递给 BindGrid 函数,该函数使用新的记录集填充 DataGridView。

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++;
    


private void Page_Click(object sender, EventArgs e)

    Button btnPager = (sender as Button);
    this.BindGrid(int.Parse(btnPager.Name));


public class Page

    public string Text  get; set; 
    public string Value  get; set; 
    public bool Selected  get; set; 

【讨论】:

【参考方案4】:

解决这个问题的另一种方法:

public class PagedGrid : DataGridView
    
        Paging pg;
        SQLQuery s;
        public void SetPagedDataSource(  SQLQuery s, BindingNavigator bnav)
        
            this.s = s;
            int count = DataProvider.ExecuteCount(s.CountQuery);
            pg = new Paging(count, 5);
            bnav.BindingSource = pg.BindingSource;
            pg.BindingSource.PositionChanged += new EventHandler(bs_PositionChanged);
            //first page
            string q = s.GetPagingQuery(pg.GetStartRowNum(1), pg.GetEndRowNum(1), true);
            DataTable dt = DataProvider.ExecuteDt(q);
            DataSource = dt;
        

        void bs_PositionChanged(object sender, EventArgs e)
        
            int pos = ((BindingSource)sender).Position + 1;
            string q = s.GetPagingQuery(pg.GetStartRowNum(pos), pg.GetEndRowNum(pos), false);
            DataTable dt = DataProvider.ExecuteDt(q);
            DataSource = dt;
        

        public void UpdateData()
        
            DataTable dt = (DataTable)DataSource;
            using (SqlConnection con = new SqlConnection(DataProvider.conStr))
            
                con.Open();
                SqlDataAdapter da = new SqlDataAdapter(s.CompleteQuery, con);
                SqlCommandBuilder cb = new SqlCommandBuilder(da);
                da.UpdateCommand = cb.GetUpdateCommand();
                da.InsertCommand = cb.GetInsertCommand();
                da.DeleteCommand = cb.GetDeleteCommand();
                da.Update(dt);
            
            MessageBox.Show("The changes are committed to database!");
        
    


  /// <summary>
    /// Gives functionality of next page , etc for paging.
    /// </summary>
    public class Paging
    
        public int _totalSize = 0;
        private int _pageSize = 0;

        public int TotalSize
        
            get
            
                return _totalSize;
            
            set
            
                if (value <= 0)
                
                    throw new ArgumentException();
                
                _totalSize = value;
            
        

        public int PageSize
        
            get
            
                return _pageSize;
            
            set
            
                if (value <= 0)
                
                    throw new ArgumentException();
                
                _pageSize = value;
            
        

        public Paging(int totalSize, int pageSize)
        
            this.TotalSize = totalSize;
            this.PageSize = pageSize;
        

        public int GetStartRowNum(int PageNum)
        
            if (PageNum < 1)
            
                throw new Exception("Page number starts at 1");
            
            if (PageNum > GetPageCount())
            
                throw new Exception("Page number starts at " + GetPageCount().ToString());
            
            return 1 + ((PageNum - 1) * _pageSize);
        

        public int GetEndRowNum(int PageNum)
        
            if (PageNum < 1)
            
                throw new Exception("Page number starts at 1");
            
            if (PageNum > GetPageCount())
            
                throw new Exception("Page number starts at " + GetPageCount().ToString());
            
            return _pageSize + ((PageNum - 1) * _pageSize);
        

        public int GetPageCount()
        
            return (int)Math.Ceiling(TotalSize / (decimal)PageSize);
        

        public bool IsFirstPage(int PageNum)
        
            if (PageNum == 1)
            
                return true;
            
            return false;
        

        public bool IsLastPage(int PageNum)
        
            if (PageNum == GetPageCount())
            
                return true;
            
            return false;
        
        private int _currentPage = 1;
        public int CurrentPage
        
            get
            
                return _currentPage;
            
            set
            
                _currentPage = value;
            
        
        public int NextPage
        
            get
            
                if (CurrentPage + 1 <= GetPageCount())
                
                    _currentPage = _currentPage + 1;
                
                return _currentPage;
            
        

        public int PreviousPage
        
            get
            
                if (_currentPage - 1 >= 1)
                
                    _currentPage = _currentPage - 1;
                
                return _currentPage;
            
        
        private BindingSource _bindingSource = null;
        public BindingSource BindingSource
        
            get
            
                if (_bindingSource == null)
                
                    _bindingSource = new BindingSource();
                    List<int> test = new List<int>();
                    for (int i = 0; i < GetPageCount(); i++)
                    
                        test.Add(i);
                    
                    _bindingSource.DataSource = test;
                
                return _bindingSource;
            

        
    


    /// <summary>
    /// Query Helper of Paging
    /// </summary>
    public class SQLQuery
    

        private string IDColumn = "";
        private string WherePart = " 1=1 ";
        private string FromPart = "";
        private string SelectPart = "";

        public SQLQuery(string SelectPart, string FromPart, string WherePart, string IDColumn)
        
            this.IDColumn = IDColumn;
            this.WherePart = WherePart;
            this.FromPart = FromPart;
            this.SelectPart = SelectPart;

        

        public string CompleteQuery
        
            get
            
                if (WherePart.Trim().Length > 0)
                
                    return string.Format("Select 0 from 1 where 2 ", SelectPart, FromPart, WherePart);
                
                else
                
                    return string.Format("Select 0 from 1 ", SelectPart, FromPart);
                
            
        

        public string CountQuery
        
            get
            
                if (WherePart.Trim().Length > 0)
                
                    return string.Format("Select count(*) from 0 where 1 ", FromPart, WherePart);
                
                else
                
                    return string.Format("Select count(*) from 0 ", FromPart);

                
            
        



        public string GetPagingQuery(int fromrow, int torow, bool isSerial)
        
            fromrow--;
            if (isSerial)
            
                return string.Format("0 where 1 >= 2 and 1 <= 3", CompleteQuery, IDColumn, fromrow, torow);
            
            else
            
                string select1 = "";
                string select2 = "";
                if (WherePart.Trim().Length > 0)
                
                    select1 = string.Format("Select top 3 0 from 1 where 2 ", SelectPart, FromPart, WherePart, torow.ToString());
                    select2 = string.Format("Select top 3 0 from 1 where 2 ", SelectPart, FromPart, WherePart, fromrow.ToString());
                
                else
                
                    select1 = string.Format("Select top 2 0 from 1 ", SelectPart, FromPart, torow.ToString());
                    select2 = string.Format("Select top 2 0 from 1 ", SelectPart, FromPart, fromrow.ToString());
                
                if (fromrow <= 1)
                
                    return select1;
                
                else
                
                    return string.Format("0 except 1 ", select1, select2);
                

            
        


    

使用它:

 private void Form1_Load(object sender, EventArgs e)
        
            SQLQuery s = new SQLQuery("*", "table", "", "id");
            pagedGrid1.SetPagedDataSource(s, bindingNavigator1);
        

注意:这里不包含DataPrivier类,它是一个简单的类,可以从任何来源返回数据表。

【讨论】:

【参考方案5】:

试试这个, 此代码适用于 OleDb,但也适用于 SqlServer 连接。 dt(DataTable)对象填充了选定的页面行,假设页面以1(不是0)开始

public DataTable getData(string sql, int pgNo, int totalRows) 

DataTable dt = null;
        using (OleDbConnection conn = new OleDbConnection(connStr))
        
            try
            
                DataSet ds;
                conn.Open();
                ds = new DataSet();
                OleDbDataAdapter adapter = new OleDbDataAdapter(sql, conn);
                adapter.Fill(ds, (pgNo-1)*totalRows, totalRows, "Table");
                conn.Close();
                dt = ds.Tables[0];
            
            catch (Exception ex)
            if (conn != null) conn.Dispose();
return dt;

【讨论】:

【参考方案6】:

使用 RadGridView for WinForms 进行分页模拟是可能的,尤其是在我们充分利用 LINQ 的情况下。这种方法还为我们提供了另一个优势——客户端性能。数据处理(过滤、排序和分页)显然是由 SQL 服务器完成的,它针对这些事情进行了全面优化,而不是应用程序。客户端一次只处理和显示一页,而不是所有百万条记录。这里我不使用 RadGridView 的虚拟模式 - 这是一个更高级的博客文章的主题。 这个链接我帮你:paging-with-radgridview https://www.telerik.com/blogs/emulating-paging-with-radgridview-for-winforms-and-linq-with-1-million-records

代码是:

private void BindGrid()

 this.radGridView1.GridElement.BeginUpdate();

 IQueryable queryable = new DataClasses1DataContext().MyTables.AsQueryable();

 if (!String.IsNullOrEmpty(where))
    
        queryable = queryable.Where(where);
    

 if (!String.IsNullOrEmpty(orderBy))
    
        queryable = queryable.OrderBy(orderBy);
    

    radGridView1.DataSource = queryable.Skip(currentPageIndex * pageSize).Take(pageSize);

 this.radGridView1.GridElement.EndUpdate(true);

    EnableDisablePager();

【讨论】:

【参考方案7】:

我在我的 datagridview 上进行了手动分页。我希望这会有所帮助

private void btnBack_Click(object sender, EventArgs e)
    
        int a = int.Parse(lblmin.Text);
        int b = int.Parse(lblmax.Text);
        int c = a - 100;
        int d = b - 100;

        if (lblmin.Text != "1")
        
            String name = "Main";
            String constr = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" +
                            "C:\\BBISDatabase\\Data.xlsx" +
                            ";Extended Properties='Excel 8.0;HDR=YES;';";

            OleDbConnection con = new OleDbConnection(constr);
            OleDbCommand oconn = new OleDbCommand("Select * From [" + name + "$] where IDs between " + c.ToString() + " and " + d.ToString() + "", con);
            con.Open();

            OleDbDataAdapter sda = new OleDbDataAdapter(oconn);
            DataTable data = new DataTable();
            sda.Fill(data);
            dgMain.DataSource = data;
            lblcount.Text = c.ToString();
            lblmax.Text = d.ToString();
        
        else
        
            btnBack.Visible = false;
        
    

    private void btnNext_Click(object sender, EventArgs e)
    

        int a = int.Parse(lblmin.Text);
        int b = int.Parse(lblmax.Text);
        int c = b + 1;
        int d = b + 100;

        String name = "Main";
        String constr = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" +
                        "C:\\BBISDatabase\\Data.xlsx" +
                        ";Extended Properties='Excel 8.0;HDR=YES;';";

        OleDbConnection con = new OleDbConnection(constr);
        OleDbCommand oconn = new OleDbCommand("Select * From [" + name + "$] where IDs between "+c.ToString()+" and "+d.ToString()+"", con);
        con.Open();

        OleDbDataAdapter sda = new OleDbDataAdapter(oconn);
        DataTable data = new DataTable();
        sda.Fill(data);
        dgMain.DataSource = data;
        lblmin.Text = c.ToString();
        lblmax.Text = d.ToString();
        btnBack.Visible = true;

    

我把这段代码放在 form_load() 上:

lblmin.Text = "1";

【讨论】:

【参考方案8】:

我的回答晚了 10 年,我无法开始解释原因。但我认为重要的是我可以提供一些东西。 :D

我喜欢以最简单的方式解决问题,到目前为止,这是我使用的最简单的方式。如果它有任何问题,很高兴修复它。

using System;
using System.Data;
using System.Windows.Forms;
using System.Data.SqlClient;
using System.Drawing;

namespace WindowsFormsApplication1

    public partial class Form1 : Form
    
        SqlDataAdapter pagingAdapter;
        DataSet pagingDS;
        int scrollVal; // This defines how many more data sets there are to load
        int rowsPerPage = 10; // This defines the total number of rows to show

        public Form1()
        
            InitializeComponent();
            scrollVal = 0;
        

        private void BtnShowresults_Click(object sender, EventArgs e)
        
            string connectionString = "Data Source=.;Initial Catalog=pubs;Integrated Security=True";
            string sql = "SELECT * FROM Authors";
            SqlConnection connection = new SqlConnection(connectionString);
            pagingAdapter = new SqlDataAdapter(sql, connection);
            pagingDS = new DataSet();
            connection.Open();

            //This part will get the total number of records from the query
            pagingAdapter.Fill(dataSetProjects);
            DataTable dataTable = pagingDS.Tables[0];
            int rowCount = Convert.ToInt32(dataTable.Rows.Count);
            this.btnShowresults.Tag = rowCount; // We set it to the button tag

            pagingAdapter.Fill(pagingDS, scrollVal, rowsPerPage, "Authors_table");
            connection.Close();
            dataGridView1.DataSource = pagingDS;
            dataGridView1.DataMember = "Authors_table";
        

        private void btnPrevious_Click(object sender, EventArgs e)
        
            if (scrollVal < = 0)
            
                scrollVal = 0;
             else
            
                scrollVal -= rowsPerPage;
            
            pagingDS.Clear();
            pagingAdapter.Fill(pagingDS, scrollVal, rowsPerPage, "authors_table");
        

        private void BtnNext_Click(object sender, EventArgs e)
        
            Button btnShowresults = (Button)pnSearch.Controls["btnShowresults"];
            int resCount = Convert.ToInt32(btnShowresults.Tag);
            if (scrollVal <= resCount)
            
                scrollVal = rowsPerPage;
             else 
            
                scrollVal = rowsPerPage;
            
            pagingDS.Clear();
            pagingAdapter.Fill(pagingDS, scrollVal, rowsPerPage, "authors_table");
        
    

此代码可在 http://csharp.net-informations.com/datagridview/csharp-datagridview-paging.htm 上找到。它有一些我需要修复的错误。认为这是一个经过清理的版本。

【讨论】:

似乎这个解决方案会一次加载整个数据集。即如果有 500 万条记录,则所有记录都将被拉入数据集中。对吗? 差不多!但只会显示您在rowsPerPage 中定义的内容

以上是关于我们如何在winform的datagridview中进行分页的主要内容,如果未能解决你的问题,请参考以下文章

如何让c#winform 根据datagridview数据筛选 filter

C# winform datagridview如何计算统计

winform dataGridView中如何添加单选按钮列?

winform中获取datagridview如何获取选中的行,返回值object

winform如何从DataGridView中从右键菜单获取一行数据

c# winform datagridview界面上的行删了,但datagridview数据源没有同步如何解决