"Categorized" DataGridView (windows forms


Adam Clauss

OK, I've really been struggling with the best way to go about this.

I have a read-only DataGridView bound via a BindingSource to a particular
table in a strongly typed DataSet/DataTable. I can sort, and everything
works fine.

But, rather than having a column header and then ALL the rows, I want to
have the various rows grouped into categories. Categories can have a
different number of rows, including NO rows (although the category header
should still show).

For example:
| Col1 | Col2 | Col3 |
| Category1 Title Here |
| r1c1 | r1c2 | r1c3 |
| r2c1 | r2c2 | r3c3 |
| r3c1 | r3c2 | r3c3 |
| Category2 Title Here |
| r4c1 | r4c2 | r4c3 |
| r5c1 | r5c2 | r5c3 |

Hopefull that text comes out close to correct.

So ALL my rows are still coming from one datatable, but (despite the fact
that I have the rows sequentially numbered) the rows for a given category
may very likely be spread out throughout the datatable.
The entire DataGridView should still scroll as one large list (individual
categories do not scroll independently).

I've tried a couple different approaches to this:
1) This is something of a migration from an existing web-based design. So,
I thought to best give me that functionality, I could use a FlowLayoutPanel
with a separate DataGridView for each category. The first category would
have it's column headers off, the others would be turned off. Upon the
first grid sorting, I would programmatically force the sort upon the other

This gave me several problems... first the FlowLayoutPanel was a PITA to
use. To prevent individual scrolling, I had to get the individual
DataGridViews to constantly resize themselves as their container
resized/rows were added (text of a cell might wrap). This... sorta worked,
but the second datagrid appeared where it was supposed to. Sometimes NEXT
to the previous datagridview, sometimes below it.
Other problem with this approach is keeping the columns aligned. I wanted
the entire object to more or less fill (horizontally) it's container. For
whatever reason (I think an issue with the FlowLayoutPanel), the second
DataGridView would never size itself as wide as the first.

2) Other option I tried was going back to one 'large' DataGridView. This
would give me the columns aligned like I wanted as well as scroll the entire
thing together. My thought was, derive my own custom "binding source" which
would actually itself a separate BindingSource object for each of the
categories (each would have an appropriate filter set on it). It would then
be my derived source's job to "concatentate" the lists as necessary to
provide to the DataGridView as well as pass on Sorting information to the
individual BindingSources. These concatenated lists would contain "special"
items in place for the category headers. An event handler for RowDataBound
could then detect these special items and change row appearance

This didn't work out either. Deriving directly from BindingSource, I
couldn't seem to actually intercept sending of the list of items to the
datagridview. I overrode a couple things (the implemented GetEnumerator(),
indexer [], etc). GetEnumerator() was never called. The indexer did get
called, but always with an index of 0 (which, comparing to the return value
of base was jsut returning the entire DataSet... or DataTable, I forget
which - in either case, the indexer was not being used to retrieve each

Any thoughts about a better way to go about this? Was I heading down the
right path with either of these? Am I just completely in left field?

Marc Gravell

I don't know about inserting an extra header row (this will be a pain
to combine with data-binding) - however, to simply enforce sub-
sorting, how about the following; look for 2 posts by me around 8 Jan,
12:50 - the first is usage, the second is the main code. The usage
example given just pushes things into a footer, but the code doesn't
care about that - it just injects an additional sort, so it should
work simply sorting on the category...



Adam Clauss

I know it's been a few days, not sure if you'll still see this or not.

Thanks for the sample, that is definately a useful starting point.

I'm running into a problem with the category rows.

I modified .Count and .Item to appropriately return items for the extra rows
for the categories, but it seems (through trial and error) that the
DataGridView blows up if each of it's rows do not come from the SAME
DataView (even if the different DataViews have the same type - though not
instance - of underlying DataTable). Since my category rows do not actually
exist in the underlying DataTable, I created a new DataTable (using same
strongly typed object as the "real" data) and a corresponding DataView on
this to provide the category rows. Unfortunately, when I return those rows
in the indexer property, either I get an exception thrown or the
datagridview's OnDataError fires saying something along the lines of "Column
'Id' does not belong to table Events." Where 'Id' is the first column in the
table, and Events is the name of the table.

I'm starting to wonder if another approach might end up better. Maybe I
need to avoid the data binding concept for what I'm trying to do. I wonder
if setting the grid up in virtual mode might be better? I call my same
object to retrieve counts, items, perform sorting, etc, but I don't have to
worry about giving the grid rows from multiple views, I just have to
manually fill in the cells myself. You think that might be worthwhile to

Marc Gravell

When the binding gets ridiculously complex, it may indeed be time to forget
about binding.


Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question