博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

C# DataGridView合计行完整解决方法、用户体验深刻、超实用

Posted on 2010-10-27 09:55  实用  阅读(20599)  评论(28编辑  收藏  举报

 

    在网络上看过很多关于DataGridView合计的设计及源码,搜到了很多相同的文章(都是相互复制),效果不如人意,   很多的人写的解决办法如下几条:

  1. DataGridView的最后一行作为合计行,每增加或删除一行后重新计算合计行。
  2. 用两个大小相同的DataGridView,一个是数据表格,一个是合计表格。
  3. 第三个是用Table类SUM增加一条合计行数据,再显示到DataGridView中。
  4. 干脆用第三方控件。。。。。。。。

  以上出现的问题:

  合计行不能显示在DataGridView界面的最下方,用户只能滚条到表格最后才能看到合计。

  如果用两个DataGridView,我想性能怎么样,大家可想而知。

  如果用Table类SUM一条,同样会产生只能要最后一行看到,如果别人不使用Table显示到DataGridView中怎么办。

 

上述的都不能很好的解决DataGridView合计行,以下是我个人设计原理与说明:

  首先我们解决的是不管用什么方式填充DataGridView数据都能够合计数据。

  必须显示在DataGridView界面的最下方,这样用户体验深刻一点。

从上我们可以看到,我们要做到合计行的话,我们必须在表现层(UI)做,不要在逻辑层与数据层做,(如果出错的话只是显示错误)

最终效果如下:

 

 合计我使用的是Lable对象。DataGridView需要处理的事件有单元格的数据改变事件CellValueChanged,滚动条事件,列宽事件,这件事件发生后重绘Lable及计算所需要列数据。

 定义对象:Lable对象名为FootSumLabel,DataGridView对象名为DetailDataGrid

 

代码
//定义类的私有变量,两个是滚动条
HScrollBar hs;
VScrollBar vs;
//合计数值
decimal fSumQty = 0, fSumCBAmount = 0;

//加载数据时先注册DetailDataGrid的滚动条事件,在类的构造时注册
 //DetailDataGrid类中包括有HScrollBar,VScrollBar如下
//hs_ValueChanged,vs_ValueChanged两个事件都重绘FootSumLabel,即FootSumLabel.Invalidate();这一句语句

hs
= ((HScrollBar)this.DetailDataGrid.Controls[0]);
vs
= ((VScrollBar)this.DetailDataGrid.Controls[1]);
hs.ValueChanged
+= new EventHandler(hs_ValueChanged);
vs.ValueChanged
+= new EventHandler(vs_ValueChanged);

//DetailDataGrid的CellValueChanged事件调用sumdata();
//FootSumLabel的重绘Paint事件
private void FootSumLabel_Paint(object sender, PaintEventArgs e)
{
int count = DetailDataGrid.Columns.Count;
DataGridViewColumnCollection Columns
= this.DetailDataGrid.Columns;

Graphics grf
= e.Graphics;
int x = this.DetailDataGrid.RowHeadersWidth - 2;
StringFormat strfmt
= new StringFormat();
strfmt.Alignment
= StringAlignment.Far;
for (int i = 0; i < count; i++)
{
x
+= Columns[i].Width;
if (i == 4)
{
int xx = x + Columns[i + 1].Width;
grf.DrawString(
string.Format("{0:F2}", fSumQty), this.FootSumLabel.Font, Brushes.Black, xx - hs.Value, 3, strfmt);
}
if (i == 7)
{
int xx = x + Columns[i + 1].Width;
grf.DrawString(
string.Format("{0:F2}", fSumCBAmount), this.FootSumLabel.Font, Brushes.Black, xx - hs.Value, 3, strfmt);
}
}
}
//合计数值函数
private void sumdata()
{
fSumQty
= 0;
fSumCBAmount
= 0;
DataGridViewRowCollection rows
= this.DetailDataGrid.Rows;
foreach (DataGridViewRow row in rows)
{
fSumQty
+= Convert.ToDecimal(row.Cells["fQty"].Value);
fSumCBAmount
+= Convert.ToDecimal(row.Cells["fAmount"].Value);
}
//重画
this.FootSumLabel.Invalidate();
}

 

以上代码可以自行加工成一个类,DataGridView调整列宽的事件只要调用重绘FootSumLabel就可以了。如果有不正之处请指出。

如果要转帖请注明出处:http://www.cnblogs.com/NetWZ/articles/1862097.html  作者:.NetWZ