DataGridView提供数据的显示和排序功能,但没有合计的功能,本人曾想过通过绑定DataView,然后直接给DataView增加一个,合计是可以显示出来,但通过列标题排序就很难控制了,绑定的做法很麻烦,因为很多动作不受控。绑定不行,只能自己创建DataGridView的列和行了,自己控制排序等。
为DataGridView增加列和行:
/// <summary>
/// 根据DataTable创建DataGridView。
/// </summary>
/// <param name="table"></param>
private void BuidGrid(DataTable table)
{
for (int i = 0; i < table.Columns.Count; i++)
{
DataColumn dcol = table.Columns[i];
DataGridViewColumn column = new DataGridViewColumn(new DataGridViewTextBoxCell());
dtgCount.Columns.Add(column);
column.SortMode = DataGridViewColumnSortMode.Automatic;
column.HeaderText = dcol.ColumnName;
column.Name = dcol.ColumnName;
if (i == 0)
{
column.DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleLeft;
}
else
{
column.DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter;
if (i == table.Columns.Count - 1)
column.DefaultCellStyle.BackColor = Color.Yellow;
}
}
foreach (DataRow row in table.Rows)
{
int index = dtgCount.Rows.Add();
DataGridViewRow vRow = dtgCount.Rows[index];
for (int i = 0; i < table.Columns.Count; i++)
{
vRow.Cells[i].Value = row[i];
}
}
//增加多一个合计的行
int countIndex = dtgCount.Rows.Add();
DataGridViewRow countRow = dtgCount.Rows[countIndex];
countRow.Cells[0].Value = "合计";
for (int i = 1; i < table.Columns.Count; i++)
{
countRow.Cells[i].Value = table.Compute("Sum([" + table.Columns[i].ColumnName + "])", "");
countRow.DefaultCellStyle.BackColor = Color.Yellow;
}
}
这样合计行就在最下面了,现在要解决的是排序的问题了,在上面的数据中,除了第一列,其他列为Int32类型,合计行好像是字符串类型,没有深入研究原因。
private void dtgCount_SortCompare(object sender, DataGridViewSortCompareEventArgs e)
{
if (e.Column.Index == 0)
{
if (dtgCount.Rows[e.RowIndex1].Cells[0].Value.ToString() == "合计")
{
if (e.Column.HeaderCell.SortGlyphDirection == SortOrder.Ascending)
e.SortResult = 1;
else
e.SortResult = -1;
}
else if (dtgCount.Rows[e.RowIndex2].Cells[0].Value.ToString() == "合计")
{
if (e.Column.HeaderCell.SortGlyphDirection == SortOrder.Ascending)
e.SortResult = -1;
else
e.SortResult = 1;
}
else
e.SortResult = System.String.Compare(e.CellValue1.ToString(), e.CellValue2.ToString());
}
else
{
if (dtgCount.Rows[e.RowIndex1].Cells[0].Value.ToString() == "合计")
{
if (e.Column.HeaderCell.SortGlyphDirection == SortOrder.Ascending)
e.SortResult = 1;
else
e.SortResult = -1;
}
else if (dtgCount.Rows[e.RowIndex2].Cells[0].Value.ToString() == "合计")
{
if (e.Column.HeaderCell.SortGlyphDirection == SortOrder.Ascending)
e.SortResult = -1;
else
e.SortResult = 1;
}
else
{
string strc1 = e.CellValue1.ToString();
string strc2 = e.CellValue2.ToString();
int c1 = string.IsNullOrEmpty(strc1) ? 0 : Convert.ToInt32(strc1);
int c2 = string.IsNullOrEmpty(strc2) ? 0 : Convert.ToInt32(strc2);
int result = c1 - c2;
e.SortResult = result > 0 ? 1 : (result < 0 ? -1 : 0);
}
}
e.Handled = true;
}
排序的算法测试了很长时间,原因是不很清楚系统的快速排序算法,原以为合计行在最后,所以只对e.RowIndex2作判断,结果总是出问题,系统自动退出,可能排序使用的是异步线程吧,在系统里捕捉不到异常的,后来对e.RowIndex1和e.RowIndex2分别作判断,并根据SortOrder来确定返回的值,问题解决。在比较中可能有些操作效率不高,使用者可根据需要修改。
如果想封装为通过的控制,可以重写DataSource属性,通过反射来生成行和列;重写OnSortCompare方法等,由于使用不多,所以本人只使用上面的方法,代码量也不多,比较灵活。