2009-06-07 4 views
1

Я унаследовал некоторый код, который применяет фильтр к datagrid, фильтр работает, но невероятно медленный, когда в datagrid есть 500+ строк (он зависает с более чем 500, отлично работает со 100 строками), фильтр в основном говорит «показать мне всех, кто заплатил» или «показать мне всех в X стране» и т. д.C# Почему этот цикл настолько медленный?

Список строк, соответствующих фильтру (отфильтрованный ниже), создается мгновенно.

 if (comboBoxFilterCondition.Text == "Contains") 
     { 
      strSearchFilter += string.IsNullOrEmpty(txtFilterValue.Text) ? " IS NULL" : " LIKE '%" + txtFilterValue.Text + "%'"; 
     } 

     FilterRows(strSearchFilter); 

// ....

private void FilterRows(string strSearchFilter) 
    { 
      DataTable table = dataGridView1.DataSource as DataTable; 
      if (table != null) 
      { 
       List<DataRow> filteredRows = new List<DataRow>(table.Select(strSearchFilter)); //<----Very quick to here 

       CurrencyManager cm = (CurrencyManager)BindingContext[dataGridView1.DataSource]; 
       cm.SuspendBinding(); 
       foreach (DataGridViewRow row in dataGridView1.Rows) 
       { 
        row.Visible = filteredRows.Contains(((DataRowView)row.DataBoundItem).Row); //<---Stuck here 
       } 
       cm.ResumeBinding(); //<----------Doesn't arrive here 

// ..... }

Любые идеи? Спасибо всем

ответ

0

Мое лучшее предположение, что это имеет какое-то отношение к тому, как он сравнивает два экземпляра DataRow. Попробуйте заменить

List<DataRow> filteredRows = new List<DataRow>(table.Select(strSearchFilter)); 

с

HashSet<DataRow> filteredRows = new HashSet<DataRow>(table.Select(strSearchFilter)); 
+0

Is Hashset in .net 3.5? Я использую .net 2.0. Спасибо – 2009-06-08 00:07:50

+0

Да, это .NET 3.5 вещь – AgileJon

12

Там нет причин, чтобы сделать фильтрацию самостоятельно. Если datagridview привязан к DataTable (и кажется, что он есть), просто используйте свойство DataTable.DefaultView.RowFilter. Пример прихода ...

Хорошо, я создал простую форму с DataGridView и двумя кнопками. На первом нажатии кнопки он применяет DataTable, а на втором он фильтрует его:

public partial class Form1 : Form 
{ 
    public Form1() 
    { 
     InitializeComponent(); 
    } 

    private void button1_Click(object sender, EventArgs e) 
    { 
     DataTable table = new DataTable(); 
     table.Columns.Add("Name", typeof(string)); 
     table.Columns.Add("Age", typeof(int)); 
     table.Rows.Add("John", 25); 
     table.Rows.Add("Jack", 34); 
     table.Rows.Add("Mike", 17); 
     table.Rows.Add("Mark", 54); 
     table.Rows.Add("Frank", 37); 

     this.dataGridView1.DataSource = table; 
    } 

    private void button2_Click(object sender, EventArgs e) 
    { 
     var table = this.dataGridView1.DataSource as DataTable; 
     table.DefaultView.RowFilter = "Age > 30"; 

    } 

При нажатии на вторую кнопку, сетка будет фильтруются автоматически. Это должно работать намного быстрее, чем делать это вручную самостоятельно. Посмотрите на эту ссылку, которую я показал вам ранее, а также эту: http://msdn.microsoft.com/en-us/library/system.data.datacolumn.expression.aspx для получения дополнительной информации о создании выражения фильтра.

+0

Я бы не рекомендовал использовать представление по умолчанию ... вам могут понадобиться скрытые данные где-то в другом месте, и это не будет отображаться в представлении по умолчанию, если вы это сделаете. Я думаю, что лучше создать новый DataView на столе. В противном случае, хороший ответ, я его проголосую;) –

1

Причина, по которой это возможно, заключается в том, что каждый раз, когда вы вызываете метод Contains, он должен перебирать все строки в списке filtersRows, пока не найдет тот, который вы ищете. Это означает, что вы произвольно зацикливаете до 500 раз каждый раз через цикл.

У BFree есть правильный ответ о том, как решить проблему. Однако я добавлю, что если вы привязываете больше чем одну вещь к таблице, вы можете привязываться к BindingSource. Источник привязки имеет свойство фильтра, которое вы можете установить.