Chrisetiquette Chrisetiquette - 1 month ago 8
Vb.net Question

How do I keep rows highlighted in a datagridview using RowFilter?

I am using RowFilter to highlight rows in a datagridview, but when i clear the filter to view all records it removes the highlight i applied:

Sorter.DtSample.DefaultView.RowFilter = "FirstName = 'John'"
For Each R0w In Sorter.DataGridView1.Rows
R0w.defaultcellstyle.forecolor = Color.Red
Sorter.DataGridView1(0, R0w.index).Value = True
Next
Sorter.DtSample.DefaultView.RowFilter = ""

Answer

You can use CellFormatting or RowPrepaint evant to apply some formatting to rows. In this case it's enough to check the criteria for the row which the event if fired for it and apply the format to the row if required. (Thanks to Plutonix for mentioning RowPrePaint which seems to be faster than cellFormatting in this case.)

Since the event is raised just for visible rows, there would not be a performance issue even if you have too many rows. Anyway having a DataGridView with too many rows is not a good idea and in such cases you should use a mechanism like virtualization or paging.

Example

Regardless of number of records, here is an example which I colorize rows which their FirstName starts with the text you entered in TextBox1 if you press Button1. If you enter empty string in TextBox1 and press Button1 all rows will be shown in black.

To make the example working you need to have a DataGridView1, TextBox1 and Button1 on form.

Public Class Form1
    Dim dt As DataTable
    Dim filter As String = ""
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        dt = New DataTable
        dt.Columns.Add("FirstName")
        dt.Columns.Add("LastName")
        dt.Rows.Add("John", "Doe")
        dt.Rows.Add("John", "Smith")
        dt.Rows.Add("Sara", "Allen")
        Me.DataGridView1.DataSource = dt
    End Sub
    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        filter = Me.TextBox1.Text
        Me.DataGridView1.Invalidate()
    End Sub
    Private Sub DataGridView1_RowPrePaint(sender As Object, _
        e As DataGridViewRowPrePaintEventArgs) Handles DataGridView1.RowPrePaint
        If (e.RowIndex < 0 OrElse e.RowIndex = DataGridView1.NewRowIndex) Then Return
        Dim row = DataGridView1.Rows(e.RowIndex)

        If (String.IsNullOrEmpty(filter)) Then
            row.DefaultCellStyle.ForeColor = Color.Black
        Else
            Dim data = DirectCast(DataGridView1.Rows(e.RowIndex).DataBoundItem, _
                DataRowView).Row
            If data.Field(Of String)("FirstName").ToLower() _
                                                 .StartsWith(filter.ToLower()) Then
                row.DefaultCellStyle.ForeColor = Color.Red
            Else
                row.DefaultCellStyle.ForeColor = Color.Black
            End If
        End If
    End Sub
End Class

Note

If you apply RowFilter to the data table which you set as DataSource of DataGridView, it shows just filtered rows. So I didn't used it because you want to colorize filtered rows in red and others in black, so we need to show all rows.