我们如何在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这是我的解决方案:我花了将近一年的时间才找到它并为此感到自豪
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使用 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
winform dataGridView中如何添加单选按钮列?
winform中获取datagridview如何获取选中的行,返回值object