过滤没有数据绑定的DataGridView

时间:2009-08-10 15:36:23

标签: c# datagridview filter

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

甚至10k行表示用户滥用系统;表现不好的用户需要考虑,所以我需要做一些不同的事情。在没有使用数据绑定的情况下,是否有更快的方法来过滤大量的行,或者我是否需要回退清除/重新创建所有行(对于合理数量的数据,这显然更慢)?

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

3 个答案:

答案 0 :(得分:8)

我几年前遇到过这个问题(在我了解数据绑定之前)并在微软发现了一个错误帖子,说这已得到确认,但问题可能无法解决。

然而,有一些可能解决这个问题。

  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。

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

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

答案 1 :(得分:6)

如果在过滤时暂时从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());
        }
    }
    

答案 2 :(得分:0)

  1. 在代码中的某处添加这些扩展方法:

    [DllImport("user32.dll", EntryPoint = "SendMessageA", ExactSpelling = true, CharSet = CharSet.Ansi, SetLastError = true)] private static extern int SendMessage(IntPtr hwnd, int wMsg, int wParam, int lParam); private const int WM_SETREDRAW = 0xB;

    public static void SuspendDrawing(this Control target)
    {
        SendMessage(target.Handle, WM_SETREDRAW, 0, 0);
    }
    
    public static void ResumeDrawing(this Control target) { ResumeDrawing(target, true); }
    public static void ResumeDrawing(this Control target, bool redraw)
    {
        SendMessage(target.Handle, WM_SETREDRAW, 1, 0);
    
        if (redraw)
        {
            target.Refresh();
        }
    }
    
  2. 现在在循环之前添加 myDGV.SuspendDrawing(),然后在循环之后添加 myDGV.ResumeDrawing()