DataGridView.CellFormatting doesn't work when the grid is sorting
I have a datagridview control that where I need to color the rows based on a value in one of the cells in each row. I'm using the CellFormatting event like so:
Private Sub DGDisplay_CellFormatting(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellFormattingEventArgs) Handles dgDisplay.CellFormatting
Dim intRowIndex As Integer = e.RowIndex 'This is zero when sorting.....
Dim CurrentRow As DataGridViewRow = dgDisplay.Rows(intRowIndex)
Dim strTestValue As String = Cu开发者_开发问答rrentRow.Cells("Status").Value
Select Case UCase(strTestValue)
Case "WARNING"
CurrentRow.DefaultCellStyle.BackColor = Color.PeachPuff
Case "ERRMESSAGE"
CurrentRow.DefaultCellStyle.BackColor = Color.Salmon
End Select
End Sub
This works fine when the grid loads and when I scroll it, etc. But when I click on the column headers to sort the grid, e.RowIndex is always zero and all of the rows get the formatting of the first row...
Why isn't this working when the grid sorts?
EDIT: Joakim was on the right track but the following code works correctly:
Private Sub dgDisplay_CellPainting(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellPaintingEventArgs) Handles dgDisplay.CellPainting
If e.RowIndex < 0 Then
Exit Sub
End If
Dim intRowIndex As Integer = e.RowIndex
Dim CurrentRow As DataGridViewRow = dgDisplay.Rows(intRowIndex)
Dim strTestValue As String = CurrentRow.Cells("Status").Value
Select Case UCase(strTestValue)
Case "WARNING"
CurrentRow.DefaultCellStyle.BackColor = Color.PeachPuff
Case "ERRMESSAGE"
CurrentRow.DefaultCellStyle.BackColor = Color.Salmon
End Select
End Sub
For some reason, e.RowIndex is set correctly here but not on the other methods. The only thing you have to worry about here is it can be -1. But when I tried to use other methods, including PrePaint, I had to deal with it always coming up zero on a sort. If I exclude the zero case, like I excluded the negative one case about, then the first row is always white!!! Madness... I'm not sure why this works, but it does. It also produces no flicker beyond what I got using the CellFormatting event.
IF ANYONE CAN EXPLAIN THE REASON WHY e.RowIndex IS BEHAVING SO WEIRD OR OFFER A BETTER WAY OF DOING THIS THEY WILL GET THE ACCEPTED ANSWER!
I suggest you try RowPrePaint
as it lets you alter the table before it paints anything but after it has databound it.
Private Sub dgDisplay_CellPainting(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellPaintingEventArgs) Handles dgDisplay.CellPainting
If e.RowIndex < 0 Then
Exit Sub
End If
Dim intRowIndex As Integer = e.RowIndex
Dim CurrentRow As DataGridViewRow = dgDisplay.Rows(intRowIndex)
Dim strTestValue As String = CurrentRow.Cells("Status").Value
Select Case UCase(strTestValue)
Case "WARNING"
CurrentRow.DefaultCellStyle.BackColor = Color.PeachPuff
Case "ERRMESSAGE"
CurrentRow.DefaultCellStyle.BackColor = Color.Salmon
End Select
End Sub
Your problem is that DataGridView.CellFormatting
is a cell-level event, but you're using it to format the whole row.
CellFormatting
is triggered for every visible cell, and for each cell you're reformatting the entire row (via CurrentRow.DefaultCellStyle
), which then triggers more cell formatting events for the reformatted cells. This probably produces an event loop which is being escaped from internally, but which gives you a bogus value for RowIndex
.
If you change your code to only restyle the relevant cell, your problem will disappear:
Dim currentCell As DataGridViewCell = CurrentRow(e.ColumnIndex)
Followed by:
Select Case UCase(strTestValue)
Case "WARNING"
currentCell.Style.BackColor = Color.PeachPuff
Case "ERRMESSAGE"
currentCell.Style.BackColor = Color.Salmon
End Select
精彩评论