C# winform 实现对数据源多列分组可折叠的Datagridview

不能用devexpress实现
2024-11-23 02:38:45
推荐回答(1个)
回答1:

既然你提到第三方的DevExpress,不妨试一下另一个第三方控件库DotnetBar。使用其中的SuperGrid控件,可以很简单的实现以下效果。


如果自己实现的话,需要重载DataGridView的绘图相关方法,相当复杂不推荐。


很抱歉曲解你的意思了。如果不使用第三方控件而是自己开发的话,我自己试过效果并不理想,主要难点在于表格的编辑问题上。只是浏览的话倒是可以做,就你给出的截图,想要实现你需要了解以下事项。


  1. 我们看到未展开的父记录并未进行分列,而是以完整的一行显示,此效果需要在datagridview的CellPainting事件中修改绘制部分,或者在自己的继承类中重载OnCellPainting方法。由于修改事件的DataGridViewCellPaintingEventArgs e参数消除边框会连左右的边框线一同抹除,所以比较合适的做法是自己在事件处理结束后自己再画左右边框线,需要在继承类中重载,写在base.OnCellPainting(e);之后。

  2. 可以看到除了RowHeader,额外的还有一个特殊列用于放置箭头,这涉及两部分的重绘。一是该列的列头并不存在,这一点可以通过重绘第二列的来实现视觉上的覆盖;二是该列的小图标需要制定此列为图像列来实现。

  3. 如何实现点击父记录就展开自己录呢?这个相对比较简单,重载OnCellClick方法,判断需要展开记录时构建合适的数据然后直接加入DataGridView,最后整理一下显示即可。


处理以上重绘,可以实现你要的显示效果,但是数据绑定和编辑等操作会变得难以控制。


此外还有另一种思路,可以尽量避免重绘:使用多个DataGridView来”模拟“对应的视觉效果。

如你的截图所示,完全可以使用4个DataGridView来”表达“。

第一个dgv显示的是符合子记录格式的列头那一行;

第二个dgv显示的是隐藏了列头的符合父记录格式的表(自然可以直有一列,如图)。如果全表无父记录被展开,那么此dgv显示所有的父记录,位置放在第一个dgv下方;如果有一条父记录被展开,此dgv应显示包括展开的父记录在内的所有显示在其上方的父记录。

第三个dgv特定的在父记录已被展开时显示子记录的内容。该dgv应隐藏列头且需要精确计算显示位置。

第四个dgv是否存在取决于第二个dgv。当无父记录展开时不存在此dgv,反之,此dgv应显示展开的父记录下方的所有父记录。显示位置需要根据第三个dgv也就是子记录表的位置来计算。该dgv同样需要隐藏列头。


如此从上到下”连接“显示的4个dgv,可以轻而易举的模拟出你截图中的效果。问题也是一样的,数据处理稍显复杂。额外的,你需要注意维护这几个dgv间的位置关系以免在视觉上露出马脚。

两个方案中,我个人比较倾向第二种。


如果你有意实现此控件,可以追问或小纸条。