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 addingConsole.WriteLine(DateTime.Now)
around the actions, androw.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()
精彩评论