汇总 DataGridView






4.63/5 (26投票s)
带有附加 SummaryRow 的 DataGridView

引言
在开发基于 Windows 窗体的客户端-服务器应用程序时,我一直在寻找一个 DataGridView 组件,它能够显示列内容的数字聚合。例如:对 Grid 中一列显示的客户订单中的项目总数进行求和。就像 Excel 可以做的那样。我没有找到合适的解决方案,所以我决定开发自己的组件。它应该像 DataGridView 一样工作,并具有在 Grid 底部显示一行的能力。
为了重新定位和调整 SummaryRow
的大小,我重构了一些代码,这些代码取自 Robert Rhode 的优秀的 Filterable DataGrid:gridextensions.aspx。非常感谢他的出色工作。
入门
要使用 SummaryDataGridViewTest 应用程序,您必须将 Nwind.mdb 数据库复制到输出目录。
背景
对 DataGridView 和 Window-Forms 库的良好了解有助于自定义代码,但这不是必需的。 SummaryDataGridView 的使用非常简单。
Using the Code
SummaryDataGridView 控件可以像 Windows 窗体的任何其他控件一样使用,并支持设计时配置。它在设计器中有一组可用的公共属性。它的使用与 DataGridView 非常相似,因为它派生自它。要显示数据,请设置控件的 DataSource
属性。要汇总的每列都必须添加到字符串数组 SummaryColumns
中。 有关公共属性以及它们如何影响 SummaryDataGridView,请参见图 1 和图 2。
SummaryRow
将 DataGridView 的一行用作 SummaryRow 非常棘手,并带来一些问题。我没有找到将 SummaryRow 锁定在网格底部的解决方案,这对于滚动是必需的。因此,我决定使用一个带有文本框的简单控件,该控件显示在 DataGridView 下方。所有 TextBoxes 都以 DataGridView 相同的方式调整大小。此外,有必要绘制自己的水平滚动条,该滚动条将显示在我们的 SummaryControlContainer 下方,而不是使用 DataGridView 的 h 滚动条,该滚动条将显示在我们的 SummaryRow 的**上方**。 因此,很大一部分代码用于定位、调整大小和重新排序我们的 SummaryRow。 对一行中的值求和是控件最简单的部分。 处理以下 DataGridView 事件以将 SummaryRow 与 DataGridView 同步
ColumnAdded、ColumnRemoved、ColumnStateChanged、ColumnDisplayIndexChanged
有关同步的更多信息,请查看 SummaryControlContainer
类的 reCreateSumBoxes()
和 resizeSumBoxes()
方法。
SummaryRow 和 DataGridView 之间的粘合剂
一个问题是如何将 SummaryRow 附加到 DataGridView。 最简单的方法是使用 Control,然后将 DataGridView 和 SummaryRow 包含在其中。 可以通过公共属性访问内部网格。 我决定让 DataGridView 创建自己的 SummaryRow。 为了避免设计器出现问题,这仅在运行时完成。 初始化后,DataGridView 调用 ChangeParent()
方法。 此方法从其父级删除 DataGridView,在其位置创建一个面板,然后将 DataGridView 和 SummaryRow 包含在面板中。 对于 TableLayoutPanel
,我们必须在删除 DataGridView 之前确定其确切位置。
private void changeParent()
{
if (!DesignMode && Parent != null)
{
[..]
panel.Bounds = this.Bounds;
panel.BackColor = this.BackgroundColor;
panel.Dock = this.Dock;
[..]
summaryControl.Dock = DockStyle.Bottom;
this.Dock = DockStyle.Fill;
Special handling for TableLayoutPanels
if (this.Parent is TableLayoutPanel)
{
int rowSpan, colSpan;
TableLayoutPanel tlp = this.Parent as TableLayoutPanel;
TableLayoutPanelCellPosition cellPos =
tlp.GetCellPosition(this);
rowSpan = tlp.GetRowSpan(this);
colSpan = tlp.GetColumnSpan(this);
tlp.Controls.Remove(this);
tlp.Controls.Add(panel, cellPos.Column, cellPos.Row);
tlp.SetRowSpan(panel, rowSpan);
tlp.SetColumnSpan(panel, colSpan);
}
else
{
Control parent = this.Parent;
remove DataGridView from ParentControls
parent.Controls.Remove(this);
parent.Controls.Add(panel);
}
summaryControl.Controls.Add(hScrollBar);
hScrollBar.BringToFront();
panel.Controls.Add(this);
panel.Controls.Add(summaryControl);
adjustSumControlToGrid();
adjustScrollbarToSummaryControl();
resizeHScrollBar();
}
}
只读 TextBox
使用标准 Windows 窗体 TextBox 的主要问题在于,将其 ReadOnly
属性设置为 true,TextBox 的颜色会更改为 Caption(某种灰色),并且无法设置为任何其他颜色。 通常,我们希望以白色背景显示我们的 SummaryRow
。 这就是我包含自己的 TextBox 的原因。 这是一个简单的控件,因为不需要像在通常的 TextBox 中那样进行 EventHandling。 TextBox 具有 IsSummary
属性,用于指示是否应将其用于聚合。 在 OnPaint
事件中直接绘制控件。
protected override void OnPaint(PaintEventArgs e)
{
Rectangle textBounds;
textBounds = new Rectangle(this.ClientRectangle.X + 2, this.ClientRectangle.Y + 2,
this.ClientRectangle.Width - 2, this.ClientRectangle.Height - 2);
using (Pen pen = new Pen(borderColor))
{
e.Graphics.FillRectangle(new SolidBrush(this.BackColor), this.ClientRectangle);
e.Graphics.DrawRectangle(pen, this.ClientRectangle.X, this.ClientRectangle.Y,
this.ClientRectangle.Width - subWidth, this.ClientRectangle.Height - 1);
e.Graphics.DrawString(Text, Font, Brushes.Black, textBounds, format);
}
}
可以在公共属性 SumaryRowBackColor
中设置 SummaryRow
的颜色。
总结一下!
值的实际求和在方法 calcSummaries()
中完成。 从 DataGridView
的 [RowsAdded]
[RowsRemoved]
和 [CellValueChanged]
事件的 EventHandlers
调用此方法。 它遍历 DataGridView 的每一行,并汇总在 SummaryColumns 中定义的列的值。
历史
- 2009 年 5 月 10 日
- 版本 1.0