简体   繁体   中英

Hiding Row in DataGridView Very Slow

I have a DataGridView in a Winforms app that has about 1000 rows (unbound) and 50 columns. Hiding a column takes a full 2 seconds. When I want to hide about half the rows, this becomes a problem.

    private void ShowRows(string match)
    {
        this.SuspendLayout();
        foreach (DataGridViewRow row in uxMainList.Rows)
        {
            if (match == row.Cells["thisColumn"].Value.ToString()))
            { row.Visible = false; }
            else
            { row.Visible = true; }
        }
        this.ResumeLayout();
    }

I did some testing by adding by adding Console.WriteLine(DateTime.Now) around the actions, and row.Visible = false is definitely the slow bit. Am I missing something obvious, like setting IsReallySlow = false ? Or do I have to go ahead and enable Virtual Mode and code up the necessary events?

It looks to me like you should be using row filters instead.

Try using a DataView as your binding source and use DataView.RowFilter to hide rows or show rows of your choosing.

DataGridView myGridView = new DataGridView();
DataView myDataView = myTable.DefaultView;
myGridView.DataSource = myDataView; // DataView that allows row filtering

myDataView.RowFilter = string.Format("thisColumn <> '{0}'",match);  // this will hide all rows where "thisColumn" = match

In most cases the property DataGridViewAutoSizeColumnMode makes a DGV slow. Your performance increases drastically when you change all columns to Mode DataGridViewAutoSizeColumnMode.None. Afterwards you can reset it in the same way to the previous state.

For Each col As DataGridViewColumn In myDGV.Columns
   col.AutoSizeMode = DataGridViewAutoSizeColumnMode.None
Next

You will see that hiding some of 1000 columns now takes only 1-2 seconds. With other properties (SuspendLayout, Hiding the whole form etc.) I could not find any effect.

As mentioned above its the DataGridViewAutoSizeColumnMode that kills the performance. Instead of looping through every row of the DatagridView and changing the autosize mode, do it instead for the whole Datagridview , by initially turning it off and then turning it on again after you have performed the required row logic

YourDatagridView.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.None

     // Perform row visibility here...

YourDatagridView.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCells

Just a question.. Is it possible to pass that match parameter to the database query or procedure and get the rows which are not matching the records. That way you just dont have to worry about showing/hiding and It would be faster as well as you will no longer be looping. This would also work as the number of records increase with time..

Just a thought which may not be applicable for you..let me know.

To implement the optimization to speed up the hidding of rows in a DataGridViewRow based on the reset of the AutoSizeColumnsMode property you can use this class:

Public Class DataGridViewUtil
    Private dgv As DataGridView
    Private sizeColumnModeBackup(-1) As DataGridViewAutoSizeColumnMode


    Public Sub New(dgv As DataGridView)
        Me.dgv = dgv
    End Sub

    ''' <summary>
    ''' Prepare datagridview before we do the row hidding to speedup it
    ''' </summary>
    ''' <remarks>We use a method based on reseting the AutoSizeColumnMode 
    '''  property to None, therefore it will be necessary to call
    '''  HidingRowsSpeederAfer() when we finish hiding rows</remarks>
    Public Sub HidingRowsSpeederBefore()
        ReDim sizeColumnModeBackup(dgv.Columns.Count)
        For Each col As DataGridViewColumn In dgv.Columns
            sizeColumnModeBackup(col.Index) = col.AutoSizeMode
            col.AutoSizeMode = DataGridViewAutoSizeColumnMode.None
        Next
    End Sub

    ''' <summary>
    ''' Restore DataGridView state changed when HidingRowsSpeederBefore() 
    '''  was called
    ''' </summary>
    ''' <remarks>This procedure must be called after the row hidding has been
    '''   done and requires a previous call to HidingRowsSpeederBefore()</remarks>
    Public Sub HidingRowsSpeederAfter()
        If dgv Is Nothing Then
            Throw New NullReferenceException("The assigned datagridview is null")
        End If
        If sizeColumnModeBackup.Length < dgv.Columns.Count Then
            Throw New Exception("Mismatch on internal SizeColumnMode array, " &
                    "maybe you forgot to call HidingRowsSpeederBefore()")
        End If
        For Each col As DataGridViewColumn In dgv.Columns
            col.AutoSizeMode = sizeColumnModeBackup(col.Index)
        Next
    End Sub
End Class

How to use it:

    Dim dgvUtil As New DataGridViewUtil(yourDataGridView)
    dgvUtil.HidingRowsSpeederBefore()

    '... do your row hidding chores here

    dgvUtil.HidingRowsSpeederAfter()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM