Filtering a DataGridView that has no data binding

I have a DGV without data binding (no data source, etc., added manually). To filter it, I did a loop check and correctly determined the properties of the strings. This worked well with smaller test suites, but does not fully work with large ones. 1 thousand Rows filtered at 5000 / sec. 10 thousand lines, filtered only ~ 250 / sec. 50k in just 40 seconds. My guess about what happens is that every time I change the visibility of the rows, the DGV rebuilds the list of displayed rows, turning the filtering process into an O (n ^ 2) operation.

Although even 10k lines indicate that the user is abusing the system; misbehaving needs to be taken into account, so I need to do something different. Is there a faster way to filter a large number of rows than what I'm doing now, without using data binding, or do I need to refuse to clear / recreate all rows (for a reasonable amount of data, this is much slower)?

  // psuedocode.  runs slowly if more than a few thousand rows.
 foreach (DataGridViewRow row in myDGV)
 {
     row.Visible = CalculateFilter (row);
 }
+6
c # filter datagridview
source share
2 answers

I had this problem a few years ago (before I found out about data binding) and found an error message in Microsoft, stating that it was confirmed, but the problem would not be fixed.

However, there are several possibilities to solve this problem.

  • If you added rows to a datagridview, add the rows to the datatable and bind them to the datagridview.

    DataTable table = new DataTable(); table.Columns.Add("Name", typeof(String)); table.Columns.Add("...", typeof(String)); foreach (var element in list) table.Rows.Add(element.Name, element.Something); dataGridView1.DataSource = table1; table.DefaultView.RowFilter = "Name Like '...'"; 
  • Create a class that inherits from BindingList and implements IBindingList. Then bind it to your DataGridView.

  • Set DataGridView VirtualMode to true.

The second method is more complicated because you have to add your own logic to implement the FindCore method.

And you should look here: http://social.msdn.microsoft.com/Forums/en-US/winformsdatacontrols/thread/68c8b93e-d273-4289-b2b0-0e9ea644623a

+8
source share

Overall performance should improve significantly if you temporarily remove rows from dataGridView during filtering.

  • Creating a form window
  • Drop the DataGridView and four buttons into the form
  • Copy and paste this code (don't forget to add event handlers for button events)

     public partial class Form1 : Form { public Form1() { InitializeComponent(); } private Stopwatch watch = new Stopwatch(); private void Form1_Load(object sender, EventArgs e) { // populate dataGridView for (int i = 0; i < 10000; i++) dataGridView1.Rows.Add("Column", i+1, 10000 - i); for (int i = 0; i < 10000; i = i + 2) dataGridView1.Rows[i].DefaultCellStyle.BackColor = Color.Red; } // remove filter private void button1_Click(object sender, EventArgs e) { watch.Reset(); watch.Start(); foreach (DataGridViewRow row in dataGridView1.Rows) row.Visible = true; watch.Stop(); MessageBox.Show(watch.ElapsedMilliseconds.ToString()); } // add filter (hide all odd rows) private void button2_Click(object sender, EventArgs e) { watch.Reset(); watch.Start(); foreach (DataGridViewRow row in dataGridView1.Rows) { if (Convert.ToInt32(row.Cells[1].Value) % 2 != 0) row.Visible = false; } watch.Stop(); MessageBox.Show(watch.ElapsedMilliseconds.ToString()); } // remove filter (improved) private void button3_Click(object sender, EventArgs e) { watch.Reset(); watch.Start(); List<DataGridViewRow> rows = new List<DataGridViewRow>(); foreach (DataGridViewRow row in dataGridView1.Rows) { rows.Add(row); } dataGridView1.Rows.Clear(); foreach (DataGridViewRow row in rows) row.Visible = true; dataGridView1.Rows.AddRange(rows.ToArray()); watch.Stop(); MessageBox.Show(watch.ElapsedMilliseconds.ToString()); } // add filer (improved) private void button4_Click(object sender, EventArgs e) { watch.Reset(); watch.Start(); List<DataGridViewRow> rows = new List<DataGridViewRow>(); foreach (DataGridViewRow row in dataGridView1.Rows) { rows.Add(row); } dataGridView1.Rows.Clear(); foreach (DataGridViewRow row in rows) { if (Convert.ToInt32(row.Cells[1].Value) % 2 != 0) { row.Visible = false; } } dataGridView1.Rows.AddRange(rows.ToArray()); watch.Stop(); MessageBox.Show(watch.ElapsedMilliseconds.ToString()); } } 
+5
source share

All Articles