日期:2014-05-18  浏览次数:20970 次

关与 DataGridView 加合计行,最新突破
基本情况描述:
  在DataGridView最下端加一行合计行,而且这一行是冻结不动行。

探索过程:
1)有人建议用datatable的Rows.Add+Compute来合计,但是无法实现一直在底部可见,而且输入数据的时候也很难处理,是最傻的方法。
2)有人建议用在datagridview CellPainting /RowPostPainting事件往datagridview 底部画线,画值,可是有个严重的问题是,当拖动滚动条的时候会被遮盖住了,也是一种没把最根本问题解决的思路。
3)定义一个自定义控件DataGridViewFooter,能根据DataGridView的列和值自动画表格和统计值,在 DataGridView OnPaint方法里把Footer 画出来,这是一种把根本问题解决的思路,可是难度很大。
4)做用户控件(UserControl),用两个DataGridView来显示,配合VScrollBar来显示滚动,现在本人暂时用这个方法先处理,可是在加载Column的时候很不方便,要自己写代码,浪费时间。

现在重点考虑方法3,通过Reflector窥看修改datagridview难点:
  控件首先会触发OnLayout事件,把datagridview里的VScrollBar、HScrollBar、RowsHeader、ColumnHeader、Data这几个区域的位置和大小都算好,主要计算方法是PerformLayoutPrivate里的ComputeLayout,储存这些数据的是DataGridView私有变量layout。
  好,明白这里后,本人在OnLayout事件之后,利用.net的反射机制,把加上DataGridViewFooter后的布局数值设置到layout去具体代码如下:
if (base.IsHandleCreated)
  {
  Type t = this.GetType();
  FieldInfo fieldInfoLayout = t.BaseType.GetField("layout", BindingFlags.NonPublic | BindingFlags.Instance);

  if (fieldInfoLayout == null) return;

  Object layoutData = fieldInfoLayout.GetValue(this);

  if (layoutData == null) return;
  //reset layout's data and rowheader field rectangle
  Type typeLayoutData = layoutData.GetType();
  FieldInfo fieldInfoData = typeLayoutData.GetField("Data");
  FieldInfo fieldInfoRowHeaders = typeLayoutData.GetField("RowHeaders");
  MethodInfo methodInfoComputeVisibleRows = t.BaseType.GetMethod("ComputeVisibleRows", BindingFlags.NonPublic | BindingFlags.Instance);

  this._dataclient = (Rectangle)fieldInfoData.GetValue(layoutData);
  this._dataclient = new Rectangle(this._dataclient.X, this._dataclient.Y, this._dataclient.Width, this._dataclient.Height-this._datagridviewfooter.Height);

  Rectangle rectRowHeader = (Rectangle)fieldInfoRowHeaders.GetValue(layoutData);
  rectRowHeader = new Rectangle(rectRowHeader.X, rectRowHeader.Y, rectRowHeader.Width, rectRowHeader.Height - this._datagridviewfooter.Height);

  fieldInfoData.SetValue(layoutData, this._dataclient);
  fieldInfoRowHeaders.SetValue(layoutData, rectRowHeader);
  methodInfoComputeVisibleRows.Invoke(this, null);

  fieldInfoLayout.SetValue(this, layoutData); 
  }
   

  改好了,在滚动的过程中,VScroll是没有问题的,可是在HScroll就出问题了,估计是系统会触发OnColumnStateChanged了事件调用了PerformlayoutPrivate方法把布局又重新算了一遍。
  而且改了layout后,还有个问题是在edit的时候,在算FirstDisplayRowIndex的时候会出错。

  这两个问题都不得而解,所以发贴让大家再讨论一下。


------解决方案--------------------

人家给你建议吧,你说是最傻的办法。

------解决方案--------------------
顶,不错,有研究精神,CPIO实现的效果也不错.
祝楼主早日攻课难关!
------解决方案--------------------
今天与未来顶一下
------解决方案--------------------
很好 很强大