Complete Source Code: http://blogs.vbcity.com/hotdog/archive/2008/12/19/9225.aspx
Note: the code is now rewritten to be 2.0 compatible (the project was written in vs2008 with compatibility set on framework 2.0), but older designers may still have trouble compiling because of the use of newer syntax (such as automatic properties). All 'var' keywords should be replaced, but they tend to sneak in because they are so easy to use ;)
If the newer syntax is a problem for many of you, drop me a note and I'll try to remove all of those syntaxes too.
Example:
Assuming you have a form with a datagridview called dataGridView1, add this code (after setting its datasource):
var grouper = new Subro.Controls.DataGridViewGrouper(dataGridView1);
grouper.SetGroupOn("NameOfThePropertyToGroupOn");
. . .
Functionality:
The DataGridViewGrouper is a component that can be added in the forms designer or in runtime to add grouping to any existing (databound) DataGridView. Grouping can be done on existing properties of the underlying data or with a custom value function. The displayed data can be altered through the exposed Display event.
Grouped rows can be quickly selected by double clicking the group header, and the rows can be collapsed and expanded by the user.
Usage:
3 simple steps
- Add the component to the designer or create it in runtime
- Set its DataGridView property to any existing databound DataGridView
-In runtime set the GroupOn property or call any of the SetGroupOn methods to start grouping
Other settings include
-the sorting of the groups (asc,desc or none, using the lists original sources order as leading)
-if the count of rows has to be shown (the shown information can be altered by catching the Display event)
-if the property name on which is grouped has to be shown (can also be altered by the Display event)
-besides the options above, the shown group value can also be altered in the Display event.
Background:
For a while now I was facing a request to add grouping to an overview in a DataGridView. And as you may have noticed: there is no grouping functionality in the default System.Windows.Forms.DataGridView.
Now there are ways of course, by adding DataGridViewRows manually and creating the groups by adding rows, but that would screw up the underlying data binding and automatic buffering/formatting/filtering/sorting, etc. Wanted to keep the bound functionality intact, but still create group rows. The solution in itself is simply to create a wrapper source that includes those rows and the grouped rows underneath and asign that to the grid, leaving the original source unaltered, and override the grouping rows painting/editing. A theory simple enough in itself, of course the implementation was a bit more work, but still less difficult than expected.
The grouping source was created easily enough, especially with the great functionality of Linq. The trick was in seperating what the grid saw from the underlying functionality. By inheriting from BindingSource all tools were available for that job. The DataSource and DataMember properties are set by the original values of the same properties in the Grid, therefor exposing the proper 'Columns'. All adding and removing had to be done in the underlying datagrid source, so those values were overridden.
The DataGridViewGrouper component itself is assigned to a grid and the Source of the grid itself is set to the grouped source. When a group row has to be painted, it is handled by the component, the other rows follow the default behaviour. Editing for a grouprow is simply cancelled. If the original source is a BindingSource, the source's positioning is synchronized.
Note that the index of the datagridview row won't be the same as the index in the original source, so you shouldn't be getting an object out of the original source directly with the row index. Then again, you should never do that anyway ;) Use the Grid.Rows[position].DataBoundItem property instead.
Source Code
TODO:
* Now the component synchronizes navigation if the source is another BindingSource. Will look later to synchronize with any CurrencyManager.
* Adding code comments :p