2009-08-10 70 views
6

我有一个非数据绑定的DGV(没有数据源等;手动添加行)。为了过滤它,我一直在循环中进行检查,并适当地设置行的可见属性。这对于较小的测试装置来说效果很好,但在较大的测试装置的性能上完全失败。以5000 /秒过滤1k行。 10k行仅以〜250 /秒过滤。 50k只有40 /秒。我对发生的事情的假设是,每当我更改行可见性​​时,DGV都会重新生成显示行的列表,将过滤进程转换为O(n^2)操作。筛选没有数据绑定的DataGridView

尽管10k行表示用户滥用系统,行为不端的用户需要考虑,所以我需要做一些不同的事情。有没有更快的方法来筛选大量的行,而不使用数据绑定,或者我需要重新清除/重新创建所有行(对于合理数量的数据,这会显着变慢)?

 
//psuedocode. runs slowly if more than a few thousand rows. 
foreach (DataGridViewRow row in myDGV) 
{ 
    row.Visible = CalculateFilter(row); 
} 
+0

为什么行必须手动生成?如果这是一个深层次的架构问题,可能没有好的或快速的答案。 – Tom 2009-08-10 16:00:16

+0

没有提供数据源的数据库。数据后端使用xml序列化将数据记录存储在“伪可识别”文件中,并将显示值(从多个文件组合而成)作为列表结构传递出来,每个结构包含单个DGV行的数据。 – 2009-08-10 16:06:43

+0

感谢您指出。直到为时已晚,我可能都不会意识到这一点。 – 2014-01-29 13:52:43

回答

8

我几年前就有这种问题(之前我知道数据绑定),发现在微软的错误后,他说,这是确定的,但这个问题将propably不是固定的。

但是,有几种可能性来解决这个问题。

  1. 将行添加到datagridview中,将行添加到数据表并将其绑定到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 '...'"; 
    
  2. 创建一个继承自BindingList并实现IBindingList的类。然后将其绑定到您的DataGridView。

  3. 将DataGridView VirtualMode设置为true。

方法二更复杂,因为您必须添加自己的逻辑来实现FindCore方法。

你应该看看这里:http://social.msdn.microsoft.com/Forums/en-US/winformsdatacontrols/thread/68c8b93e-d273-4289-b2b0-0e9ea644623a

+0

Method1看起来可能是最好的方法。不幸的是,在这个开发周期中这可能太晚了。 msdn线程Suspend/ResumeLayout中的一个“廉价”修复程序没有任何明显的性能提升。我的假设是,虽然没有解决基本问题,但MS很友善地添加某种更改缓存布局暂停以限制我的无知会造成的损害。 – 2009-08-17 20:50:05

5

整体表现应该大大提高,如果你暂时从而过滤DataGridView中删除行。

  1. 创建一个Windows窗体应用程序
  2. 删除一个DataGridView和四个按钮形式
  3. 复制并粘贴此代码(不要忘了添加事件处理程序的按钮事件)

    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()); 
        } 
    } 
    
+0

工作。该方法还加快了最初的电网加载过程。 – 2009-10-01 15:50:55

+0

我惊呆了,它在性能上有多大的区别:我的机器上有19秒和0.1秒。帮了我很多。谢谢。 – 2014-01-29 13:49:56

+0

事实上,我还没有证实,但今天我会假设调用'dataGridView.SuspendLayout();'在更改和'dataGridView.ResumeLayout(true);'之前会有相同的效果(我喜欢包装这种类型的代码放到'x.SuspendLayout(); try {...} finally {x.ResumeLayout();}'块中,否则你的dataGridView将不会再更新ui。 – 2014-01-30 07:43:19