.netvb.netwinformsdatagridviewdatarowview

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 = ""

Solution

  • 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.