2009-08-10 32 views
6

Tôi có một DGV không databound (không có nguồn dữ liệu, vv; hàng thêm bằng tay). Để lọc nó tôi đã làm một kiểm tra trong một vòng lặp và thiết lập các hàng có thể nhìn thấy tài sản một cách thích hợp. Điều này làm việc tốt với các bộ thử nghiệm nhỏ hơn, nhưng thất bại hoàn toàn về hiệu suất với các bộ thử nghiệm lớn hơn. 1k hàng được lọc ở 5000/giây. 10 nghìn hàng được lọc chỉ ~ 250/giây. 50k chỉ với 40/giây. Giả định của tôi về những gì đang xảy ra là mỗi khi tôi thay đổi một hàng hiển thị DGV xây dựng lại một danh sách các hàng được hiển thị biến quá trình lọc thành một hoạt động O (n^2).Lọc một DataGridView không có databinding

Mặc dù thậm chí 10k hàng cho biết rằng người dùng đang lạm dụng hệ thống; người dùng có hành vi xấu cần phải được tính toán vì vậy tôi cần phải làm điều gì đó khác đi. Có cách nào nhanh hơn để lọc một số lượng lớn hàng hơn so với những gì tôi đang làm bây giờ mà không sử dụng ràng buộc dữ liệu hay tôi cần quay lại xóa/tạo lại tất cả các hàng (với số lượng dữ liệu hợp lý chậm hơn đáng kể)?

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

Tại sao các hàng phải được tạo theo cách thủ công? Có thể không có câu trả lời tốt hay nhanh nếu đây là vấn đề kiến ​​trúc sâu. – Tom

+0

Không có cơ sở dữ liệu để cung cấp nguồn dữ liệu. Phụ trợ dữ liệu sử dụng xml serialization để lưu trữ các bản ghi dữ liệu trong các tệp "pseudotable" và chuyển các giá trị hiển thị (kết hợp từ nhiều tệp) ra dưới dạng Danh sách <> của mỗi cấu trúc chứa một dữ liệu cho một hàng DGV duy nhất. –

+0

Cảm ơn bạn đã chỉ ra. Tôi có lẽ sẽ không nhận thức được điều đó cho đến khi quá muộn. –

Trả lời

8

Tôi gặp vấn đề này vài năm trước (trước khi tôi biết về dữ liệu) và tìm thấy một bài đăng lỗi tại Microsoft, nói rằng điều này được xác nhận, nhưng vấn đề sẽ không được khắc phục.

Tuy nhiên, có một vài khả năng để giải quyết vấn đề này.

  1. Được thêm hàng vào chế độ xem dữ liệu, thêm hàng vào một dữ liệu có thể định hướng và liên kết hàng với chế độ xem dữ liệu.

    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. Tạo lớp kế thừa từ BindingList và triển khai IBindingList. Sau đó liên kết nó với DataGridView của bạn.

  3. Đặt DataGridView VirtualMode thành true.

Phương pháp hai phức tạp hơn, vì bạn phải thêm logic của riêng mình để triển khai phương pháp FindCore.

Và bạn nên xem xét ở đây: http://social.msdn.microsoft.com/Forums/en-US/winformsdatacontrols/thread/68c8b93e-d273-4289-b2b0-0e9ea644623a

+0

Method1 có vẻ như đây là cách tốt nhất để làm điều đó. Thật không may, nó có thể là quá muộn trong chu kỳ dev này để làm như vậy. Sửa chữa "rẻ" trong chuỗi msdn Suspend/ResumeLayout không có bất kỳ hiệu suất đáng chú ý nào.Giả định của tôi sẽ là trong khi không sửa chữa vấn đề cơ bản MS là loại, đủ để thêm một số loại thay đổi bộ nhớ đệm bố trí hệ thống treo để hạn chế thiệt hại mà loại vô minh của tôi sẽ gây ra. –

5

Hiệu suất tổng thể sẽ được cải thiện đáng kể nếu bạn tạm thời loại bỏ các hàng từ DataGridView trong khi lọc.

  1. Tạo một ứng dụng hình thức cửa sổ
  2. Thả một DataGridView và bốn nút mẫu
  3. Sao chép và dán đoạn mã này (đừng quên để thêm xử lý sự kiện cho các sự kiện nút)

    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

Điều đó đã hiệu quả. Cách tiếp cận này cũng tăng tốc quá trình tải lưới ban đầu. –

+0

Tôi choáng váng về sự khác biệt lớn về hiệu suất mà điều này tạo ra: 19 so với 0,1 giây trên máy của tôi. Giúp tôi rất nhiều. Cảm ơn. –

+0

Thật vậy, tôi đã không xác minh điều đó, nhưng hôm nay tôi sẽ giả định một cuộc gọi đến 'dataGridView.SuspendLayout();' trước các thay đổi và 'dataGridView.ResumeLayout (true);' sẽ có cùng tác dụng (tôi thích bọc loại mã này vào một 'x.SuspendLayout(); try {...} cuối cùng là {x.ResumeLayout();}' block, nếu không dataGridView của bạn sẽ không cập nhật ui nữa nếu có lỗi gì đó. –

Các vấn đề liên quan