Windows Forms DataGrid Column Resizing
If you’ve ever tried to use the Windows Forms DataGrid then I’m sure you are frustrated. Before I start – I suggest you don’t do this, buy a third party grid control instead. I have had some good experience with the Janus grid control. All I wanted was a simple read only grid, no tree or editable columns or anything complicated, and in my case I didn't want another assembly so I had no choice and had to use the DataGrid.
There are a number of places around the internet, particularly George Shepard’s Windows Forms FAQ that help, however I couldn't find a solution that did enough.
My core problem was ensuring the columns fill the client area – as my personal view is that grid controls don’t look very good unless this is done. The DataGrid doesn’t do this as standard – but hey “how hard can it be?”
Firstly let’s write a little RecalcColumnWidths function to make the columns as wide as the grid width – make the first n-1 columns width/n pixels wide and make the final column the remainder to compensate for any rounding errors.
Then we clearly have to implement the grid’s resize event and call our RecalcColumnWidths function – so far so good, it looks ok.
First problem is how to cope with the vertical scroll bar? Sometimes it’s there, sometimes it’s not… how to tell. There’s a nice property called VerticalScrollbar, but sadly it’s protected. So this forces us to subclass the DataGrid control – and we might as well do the resizing in there too. While we’re doing that we should grab the VertScrollBar_VisibleChanged event so we can spot it appearing.
Excellent… that wasn’t too bad. Sadly we’re still not done. If the user resizes one of the columns we no longer have the columns filling the area. We could cheat and not turn on user column resizing but, to me, that’s not acceptable.
So we need to handle ColumnStyle_WidthChanged which means we need to add an event handler to the column styles… so to do that we need to grab the TableStyles_CollectionChanged event to hook our handler in.
It starts getting complicated here – as if the user sets the column width then we should be nice and try to use the setting they decide otherwise you could very easily set it right back to where it was before they resized – this makes them unhappy. We store this info per column along perhaps with a min and max width for that column and whether this column should be the column that fills the blank space.
We now have a fair sized chunk of code but we’re sorted? Right? No. All looks good, but… what if the user double clicks on a column header where there’s a separator to auto-size the column? Hmmm
Now this is a problem – for some bizarre reason it doesn’t fire a width changed event. Doh! So we need to try to figure it ourselves. Lets handle the double click event. Good. Now how to tell if a resize has happened. Well best I can think of is to check if any of the columns have changed size. If so then lets do a width readjustment.
Anyway finally I think I’ve got something reasonable. But it was a lot of work.
If you want to grab the results of this let me know and I’ll post the code.
Update: The code can be downloaded from http://www.sentient.co.uk/dataGridAutoSize.aspx