Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to force a DataGridView to fire its CellFormatting event for all cells?

We use the CellFormatting event to colour code cells in various grids all over our application.

We've got some generic code which handles export to Excel (and print) but it does it in Black & White. Now we want to change this and pick up the colour from the grids.

This question & answer has helped (and it works) ... except there's a problem with larger grids that extend beyond a single screen. The portions of the grid which haven't yet been displayed on screen are (logically) never getting their CellFormatting code fired, and so their underlying colour never gets set. As a result, in Excel, the colour coding fizzles out half way down the page.

Seems there are three solutions:

1) Tell the user he has to scroll to all parts of the grid before doing an Export to Excel. Ha! Not a serious solution

2) Programmatically scroll to all parts of the grid before doing an Export to Excel. Only slighly less horrible than (1)

3) In our Export to Excel code, fire something at the top which tells the DataGridView to paint/format its entire area e.g.

  MyDataGridView.FormatAllCells()

Is there something that does something like this???

Oh, and there is a fourth option but this will involve touching a massive amount of existing code:

4) Stop using CellFormatting event, format the cells at load time. Problem with this is we'd have to retool every grid in our application since CellFormatting is the way we've done it since year dot.

like image 581
hawbsl Avatar asked May 18 '12 11:05

hawbsl


3 Answers

I have a possible solution - In your export function access the Cell.FormattedValue property of each cell. According to Microsoft, this forces the CellFormatting event to fire.

like image 181
Rex Schrader Avatar answered Nov 09 '22 02:11

Rex Schrader


As noted in the other answers, accessing the DataGridViewCell.FormattedValue is indeed an easy way to force the CellFormatting event to be (re-)called for a specific cell. In my case, however, this property was also leading to undesirable side-effects involving the auto-resizing of the columns. While searching a long time for a workable solution, I finally encountered the following magic methods that work perfectly: DataGridView.Invalidate(), DataGridView.InvalidateColumn(), DataGridView.InvalidateRow(), and DataGridView.InvalidateCell().

These 4 methods force the CellFormatting event to be re-called only for the specified scope (cell, column, row, or whole table), and also without causing any nasty auto-resizing artifacts.

like image 42
Special Sauce Avatar answered Nov 09 '22 04:11

Special Sauce


Assuming, as @DavidHall suggests, there is no magic .FormatAllCells our only option is to stop using CellFormatting.

However, new problem here is that applying cell style formatting during load doesn’t seem to have any effect. Lots of posts out there if you Google it. Also they point out that if you put the same code under a button on the form and click it after loading (instead of in the load, the code will work ... so the grid has to be visible before styling can apply). Most advice on the topic suggests you use ... drumroll ... CellFormatting. Aargh!

Eventually found a post which suggests using the DataBindingComplete event of the grid. And this works.

Admittedly, this solution is a variant of my unwanted option "4".

like image 3
hawbsl Avatar answered Nov 09 '22 04:11

hawbsl