带分页的 DataGridView (UserControl)






4.97/5 (13投票s)
这是用于 Windows 窗体的带分页的 DataGridView 用户控件。
- DataGridViewWithPaging 用户控件源代码 - 无可执行文件 - 11.5 KB
- DataGridViewWithPaging 用户控件源代码 - 39.3 KB
- DataGridViewWithPaging 库 - 5.2 KB
引言
我创建这个用户控件是为了那些正在寻找 DataGridView 分页功能的人。很多时候,我们在 Windows 应用程序中都会使用带分页功能的 DataGridView。因此,我写这篇文章的目的是展示用户控件的创建过程,并提供带分页功能的 DataGridView。
尽管创建分页功能非常基础,但我想通过这篇文章向您展示用户控件的特性,我认为这将是学习用户控件的最佳主题。人们已经了解 DataGridView 和分页,因此无需额外的知识即可理解其功能。
它会是什么样子?
让我先向您展示这个控件的外观,这样您就知道您将要开发什么了。
创建用户控件:
我希望您已经知道如何在您的 Windows 窗体上拖放按钮、标签或文本框控件。您的项目中可能已经添加了很多窗体。同样,您可以从“右键单击项目 > 添加 > 新建项”中添加新的 用户控件。或者,如果您想创建可供其他应用程序使用的用户控件,那么您可以添加新的 Windows 窗体控件库 项目。一旦您构建了您的应用程序,它将为您提供 DLL(动态链接库)文件,以便在其他项目中使用。
如您所见,上面我们有几个按钮控件、一个文本框控件和一个 DataGridView 控件。我们将 DataGridView 的 Dock
属性设置为 Fill,这样即使我们更改用户控件的宽度和高度,它看起来也会很完美。在底部,我们创建了一个 TableLayoutPanel
,它将用于正确排列我们的按钮和文本框。TableLayoutPanel 的 Dock
属性设置为 bottom,并带有固定高度。因此,即使调整控件大小,它也不会破坏我们的设计。更改用户控件的外观和感觉后,您现在可以继续进行控件的代码隐藏部分。
我想这个介绍暂时就足够了。让我们看看 DataGridView 用户控件的代码。
我们需要在 UserControl 中公开一些属性,以便其他人可以修改它。例如:DataGridView 的宽度、DataGridView 的高度、按钮文本、页面大小、数据源等。
让我们从查看公开用户控件属性的代码开始。 首先,我们将查看最重要的属性,例如 PageSize。
private int _PateSize = 10;
public int PageSize
{
get
{
return _PateSize;
}
set
{
_PateSize = value;
}
}
PageSize 属性非常重要,没有它我们就无法设置每页要显示多少行。我们将 PageSize 的默认值设置为 10。如果您不设置 PageSize 的值,那么它将每页显示 10 行。
现在接下来我们将看一下控件的 DataSource 属性。该控件包含我们已绑定到 DataGridView 的 DataTable。尽管这不是一个非常重要的属性,但我们创建它以防用户需要所有数据而不是分页数据。
private DataTable _DataSource;
public DataTable DataSource
{
get
{
return _DataSource;
}
set
{
_DataSource = value;
}
}
其他属性,如 Width 和 Height,对于在运行时设置大小也很重要。虽然用户可以在设计时更改控件的宽度和高度,但我们可以将其添加为属性,以便在运行时进行设置。
private int _Width;
public int ControlWidth
{
get
{
if (_Width == 0)
return dataGridView1.Width;
else
return _Width;
}
set
{
_Width = value;
dataGridView1.Width = _Width;
}
}
private int _Height;
public int ControlHeight
{
get
{
if (_Height == 0)
return dataGridView1.Height;
else
return _Height;
}
set
{
_Height = value;
dataGridView1.Height = _Height;
}
}
请注意,我为 Height、Width 按钮文本属性添加了一些验证。我们需要此类验证来减少错误消息的可能性。如果用户在设置 Height 值之前尝试获取它,则会得到不正确的结果(值 0)。因此,我们在上述属性中添加了此类验证。
最后,我们将公开按钮文本属性。通常我们熟悉的分页按钮是“第一页”、“上一页”、“下一页”和“最后一页”,但有些用户希望用不同的文本显示该控件,例如大于 (>) 或小于 (<) 符号。这可以通过以下属性设置。尽管以下四个属性不是特别重要,但它们取决于用户的选择。
private string _FirstButtonText = string.Empty;
public string FirstButtonText
{
get
{
if (_FirstButtonText == string.Empty)
return btnFirst.Text;
else
return _FirstButtonText;
}
set
{
_FirstButtonText = value;
btnFirst.Text = _FirstButtonText;
}
}
private string _LastButtonText = string.Empty;
public string LastButtonText
{
get
{
if (_LastButtonText == string.Empty)
return btnLast.Text;
else
return _LastButtonText;
}
set
{
_LastButtonText = value;
btnLast.Text = _LastButtonText;
}
}
private string _PreviousButtonText = string.Empty;
public string PreviousButtonText
{
get
{
if (_PreviousButtonText == string.Empty)
return btnPrevious.Text;
else
return _PreviousButtonText;
}
set
{
_PreviousButtonText = value;
btnPrevious.Text = _PreviousButtonText;
}
}
private string _NextButtonText = string.Empty;
public string NextButtonText
{
get
{
if (_NextButtonText == string.Empty)
return btnNext.Text;
else
return _NextButtonText;
}
set
{
_NextButtonText = value;
btnNext.Text = _NextButtonText;
}
}
现在,让我们看看代码的第二部分,即 DataTable 与 DataGridView 的绑定。在这里,我们需要根据当前页面过滤数据。我们还需要更改显示当前页面的文本框信息。
public void DataBind(DataTable dataTable)
{
DataSource = dataTable;
dataGridView1.DataSource = ShowData(1);
}
当用户将 DataTable 绑定到我们自定义的 DataGridView 时,我们需要向他们显示所有数据中的第一页。因此,我们在 ShowData 私有函数中传递参数 1。上面的函数将内部调用 ShowData 函数,它将动态创建新的 DataTable。
private DataTable ShowData(int pageNumber)
{
DataTable dt = new DataTable();
int startIndex = PageSize * (pageNumber - 1);
var result = DataSource.AsEnumerable().Where((s, k) => (k >= startIndex && k < (startIndex + PageSize)));
foreach (DataColumn colunm in DataSource.Columns)
{
dt.Columns.Add(colunm.ColumnName);
}
foreach (var item in result)
{
dt.ImportRow(item);
}
txtPaging.Text = string.Format("Page {0} Of {1} Pages", pageNumber, (DataSource.Rows.Count / PageSize) + 1);
return dt;
}
ShowData 方法包含代码的不同部分。首先,它将 pageNumber 作为参数。假设用户请求第 3 页,那么它将首先检查需要从 DataSource 返回多少条记录。ShowData 函数将返回一个 DataTable,其 DataRow 计数为 PageSize。如果您的最后一页有 5 条记录,那么 DataTable 将只填充 5 条 DataRow。让我们逐一查看上面的代码。
如果你看 ShowData 函数的第 3 行,我们使用了 DataSource,它以 DataTable 的形式包含所有记录。要在 DataTable 上执行 LINQ 查询,首先需要将其转换为 Enumerable 类型。AsEnumerable 将把我们的 DataTable 转换为 Enumerable 类型。然后你可以应用基于索引的 Where 条件。where 条件中的 (s,k) 分别表示 DataRow(s) 和 Index(k)。如果用户请求第 3 页且页面大小为 10,则 startIndex 将为 20。在第 3 页,我们需要显示从 21 到 30 的数据。但是 DataRows 是基于索引存储的,因此我们需要获取从 20 到 29 的记录(包括第 20 行和第 29 行)。因此 where 子句表示返回从 20 到 (20+10=30) 的记录。但是,在右侧操作中,我们使用了 (<) 大于符号,而不是 (<=) 大于或等于。因此不会返回第 30 条记录。
然后,接下来的 foreach 循环将在 DataGridView 中创建 DataColumns。如果您不在 DataGridView 中创建数据列,那么它将无法正确显示数据。
在最后一个 foreach 循环中,我们将所需的行导入到新的 DataTable,即 dt。我们不能直接添加项目,如 dt.Rows.Add(item),因为该数据行已经与另一个 DataTable 关联。因此,我们在这里使用了 dt.ImportRow(item)。
当用户点击“首页”按钮时,我们需要显示从 第 0 个索引到 PageSize
的第一页。如您在 btnFirst_Click 事件中看到的,我们添加了对 _CurrentPage
的检查。如果用户已经在第一页,点击“首页”按钮没有任何意义。因此,我们添加了一个 MessageBox 来显示信息。如果 _CurrentPage
不是第一页,那么我们将其设置为第一页,然后内部调用 ShowData 函数并绑定 DataGridView 的 DataSource。
private void btnFirst_Click(object sender, System.EventArgs e)
{
if (_CurrentPage == 1)
{
MessageBox.Show("You are already on First Page.");
}
else
{
_CurrentPage = 1;
dataGridView1.DataSource = ShowData(_CurrentPage);
}
}
“下一页”按钮将把 DataGridView 数据导航到下一页。因此,DataGridView 会相应地更新其数据。当用户单击“下一页”按钮时,将计算最后一页,因为如果用户已经在最后一页,我们应该提示消息,告知请求的页面不存在,或者用户已经在最后一页,无法导航到下一页。如果请求的页面不是最后一页,则增加 CurrentPage 并调用 ShowData 函数。
private void btnNext_Click(object sender, System.EventArgs e)
{
int lastPage = (DataSource.Rows.Count / PageSize) + 1;
if (_CurrentPage == lastPage)
{
MessageBox.Show("You are already on Last page, you can not go to next page of Last page.");
}
else
{
_CurrentPage += 1;
dataGridView1.DataSource = ShowData(_CurrentPage);
}
}
“上一页”按钮将使 DataGridView 导航到上一页。这意味着如果您在第 3 页,点击“上一页”按钮将显示第 2 页的数据。我们还需要确保如果用户已经在第一页,则第一页没有上一页。如果请求的页面不是第一页,则递减 _currentPage
值并调用 ShowData 函数。
private void btnPrevious_Click(object sender, System.EventArgs e)
{
if (_CurrentPage == 1)
{
MessageBox.Show("You are already on First page, you can not go to previous of First page.");
}
else
{
_CurrentPage -= 1;
dataGridView1.DataSource = ShowData(_CurrentPage);
}
}
“最后一页”按钮点击事件将把网格数据导航到最后一页。为了检查用户上次请求的页面是否已经是最后一页,我们必须将其存储在某个变量中。我们创建了一个局部变量 previousPage 来存储之前请求的页面。如果前一页和最后一页索引相同,则应提示一条消息,说明用户已经在最后一页。如果用户请求的不是最后一页,则只需将最后一页索引传递给 ShowData 函数。
private void btnLast_Click(object sender, System.EventArgs e)
{
int previousPage = _CurrentPage;
_CurrentPage = (DataSource.Rows.Count / PageSize) + 1;
if (previousPage == _CurrentPage)
{
MessageBox.Show("You are already on Last Page.");
}
else
{
dataGridView1.DataSource = ShowData(_CurrentPage);
}
}
如您所见,在我们所有的按钮点击事件中,都有一些信息消息。如果您想自定义这些消息,那么您还需要为信息消息创建属性。我将此练习留给初学者。
希望您从以上代码中学到了一些东西,欢迎您的建议。如果您觉得这个控件缺少什么,请发表您的留言。历史
2012年8月24日:首次发布