2009-08-10 104 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