Performance hit due to foreach loop

Rishabh aggarwal 40 Reputation points
2023-11-11T03:54:24.8666667+00:00
private void textBox_TextChanged(object sender, EventArgs e)
{
    string filterText = textBox.Text.ToLower(); // Get the text entered in the TextBox and convert it to lowercase for case-insensitive comparison
    
    foreach (DataGridViewRow row in dataGridView.Rows)
    {
        string cellValue = row.Cells["ColumnName"].Value.ToString().ToLower(); // Replace "ColumnName" with the actual name of the column you want to filter on
        
        if (cellValue.Contains(filterText))
        {
            row.Visible = true; // Show the row if it contains the filter text
        }
        else
        {
            row.Visible = false; // Hide the row if it doesn't contain the filter text
        }
    }
}


I have an textbox in which whatever i type inside it , is used to filter the dipalyed results inside a datagridview . but this code has a performance problem due to the foreach loop . My datagridview has over 350 results and using foreach loop is just causing my old system to sleep everytime . Please suggest a better working approach with regards to my example as i have used datatable to fill up my datagridview

Windows Forms
Windows Forms
A set of .NET Framework managed libraries for developing graphical user interfaces.
1,908 questions
C#
C#
An object-oriented and type-safe programming language that has its roots in the C family of languages and includes support for component-oriented programming.
11,123 questions
{count} votes

Accepted answer
  1. KOZ6.0 6,580 Reputation points
    2023-11-11T05:51:43.5+00:00

    If you are using a DataTable as your data source, use the DefaultView's RowFilter property to filter.

    private void Form1_Load(object sender, EventArgs e) {
        bindData = new DataTable();
        bindData.Columns.Add("columnName");
        for (int i = 0x20; i < 127; i++) {
            bindData.Rows.Add(((char)i).ToString());
        }
        dataGridView1.DataSource = bindData;
    }
    
    private void textBox1_TextChanged(object sender, EventArgs e) {
        bindData.CaseSensitive = false;
        bindData.DefaultView.RowFilter = "columnName like '%" +
                                           textBox1.Text.Replace("'", "''") +
                                           "%'";
    }
    
    0 comments No comments

1 additional answer

Sort by: Most helpful
  1. Karen Payne MVP 35,461 Reputation points
    2023-11-11T10:59:06.5333333+00:00

    I recommend using a strong typed data source, usually the average developer will use a DataTable. Let's look at using a DataTable in tangent with a BindingSource.

    There are several language extensions in this case which may seem overboard but when placed into a separate class project allow them to be used in more than one project.

    In this code sample, the DataGridView DataSource points to a BindingSource which has been loaded with a DataTable.

    Then in TextChanged event we use a language extension to find text in the first column of the DataGridView. By default the filter is case insensitive.

    Filter

    Full source is mixed in with another code sample here.

    public partial class Form1 : Form
    {
        BindingSource _bindingSource = new();
        public Form1()
        {
            InitializeComponent();
            // GetCustomers returns a DataTable
            _bindingSource.DataSource = DataOperations.GetCustomers();
            dataGridView1.DataSource = _bindingSource;
            // resize columns to fit column width from database
            dataGridView1.ExpandColumns();
            FilterTextBox.TextChanged += FilterTextBox_TextChanged;
        }
    
        private void FilterTextBox_TextChanged(object sender, EventArgs e)
        {
            _bindingSource.RowFilterStartsWith("CompanyName", FilterTextBox.Text);
        }
    }
    
    public static class StringExtensions
    {
        public static string EscapeApostrophe(this string pSender) 
            => pSender.Replace("'", "''");
    }
    
    public static class BindingSourceExtensions
    {
        public static DataTable DataTable(this BindingSource sender) 
            => (DataTable)sender.DataSource;
        public static DataView DataView(this BindingSource sender) 
            => ((DataTable)sender.DataSource).DefaultView;
        public static void RowFilterStartsWith(this BindingSource sender, string field, string value, bool caseSensitive = false)
        {
            sender.DataTable().CaseSensitive = caseSensitive;
            sender.DataView().RowFilter = $"{field} LIKE '{value.EscapeApostrophe()}%'";
        }
        public static void RowFilterContains(this BindingSource sender, string field, string value, bool caseSensitive = false)
        {
            sender.DataTable().CaseSensitive = caseSensitive;
            sender.DataView().RowFilter = $"{field} LIKE '%{value.EscapeApostrophe()}%'";
        }
        public static void RowFilterEndsWith(this BindingSource sender, string field, string value, bool caseSensitive = false)
        {
            sender.DataTable().CaseSensitive = caseSensitive;
            sender.DataView().RowFilter = $"{field} LIKE '%{value.EscapeApostrophe()}'";
        }
    }
    
    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.