Click here to Skip to main content
15,901,284 members
Please Sign up or sign in to vote.
3.00/5 (2 votes)
See more:
I can't seem to figure out what's going here...I have a dataGridView with no more than 500 rows at any given time but usually around 200 or 300. I iterate through the grid and set the button text and color according user interaction. Example:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        DataGridViewButtonColumn btn;
        ContextMenuStrip ctxtStartStop;

        public Form1()
        {
            InitializeComponent();

            formatGrid();
            populateGrid();

            ctxtStartStop = new ContextMenuStrip();
            ctxtStartStop.Items.Add("START ALL");
            ctxtStartStop.Items.Add("STOP ALL");
            ctxtStartStop.ItemClicked += new ToolStripItemClickedEventHandler(ctxtMenuStrip_ItemClicked);
        }

        private void formatGrid()
        {
            btn = new DataGridViewButtonColumn();
            btn.Text = "START";
            btn.Name = "colStartStop";
            btn.HeaderText = "Start/Stop";
            btn.DefaultCellStyle.BackColor = Color.LightGreen;
            btn.DefaultCellStyle.ForeColor = Color.Black;
            btn.ReadOnly = false;
            btn.UseColumnTextForButtonValue = false;
            btn.FlatStyle = FlatStyle.Standard;
            btn.AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells;

            gridDisplay.AutoGenerateColumns = false;
            gridDisplay.AllowUserToAddRows = false;
            gridDisplay.RowHeadersVisible = false;
            gridDisplay.Columns.Add(new DataGridViewTextBoxColumn()
            {
                Name = "colSymbol",
                HeaderText = "Symbols",
                ReadOnly = true,
                AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill,
                MinimumWidth = 50
            });
            gridDisplay.Columns.Add(btn);

            gridDisplay.MouseClick += new MouseEventHandler(gridDisplay_MouseClick);
        }

        private void populateGrid()
        {
            for (int i = 0; i < 500; i++)
            {
                gridDisplay.Rows.Add("XYZ", "START");
            }
        }

        private void gridDisplay_MouseClick(object sender, MouseEventArgs e)
        {
            if (e.Button == System.Windows.Forms.MouseButtons.Left)
                return;

            int rowPosition = gridDisplay.HitTest(e.X, e.Y).RowIndex;
            int colPosition = gridDisplay.HitTest(e.X, e.Y).ColumnIndex;

            if (rowPosition == -1 && colPosition == 1)
            {
                ctxtStartStop.Show(gridDisplay.PointToScreen(e.Location));
            }
        }

        private void ctxtMenuStrip_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
        {
            if (e.ClickedItem.Text == "START ALL")
            {
                ctxtStartStop.Hide();
                startAll();
            }
            else if (e.ClickedItem.Text == "STOP ALL")
            {
                ctxtStartStop.Hide();
                stopAll();
            }
        }

        private void startAll()
        {
            string action = string.Empty;
            int idx = 1;

            for (int i = 0; i < gridDisplay.Rows.Count; i++)
            {
                var btnCell = gridDisplay.Rows[i].Cells[idx];

                action = (string)btnCell.Value;

                if (action == "START")
                {
                    btnCell.Value = "STOP";
                    gridDisplay.Rows[i].Cells["colStartStop"].Style.BackColor = Color.Red;
                    gridDisplay.Rows[i].Cells["colStartStop"].Style.ForeColor = Color.White;
                }
            }
        }

        private void stopAll()
        {
            string action = string.Empty;
            int idx = 1;

            for (int i = 0; i < gridDisplay.Rows.Count; i++)
            {
                var btnCell = gridDisplay.Rows[i].Cells[idx];

                action = (string)btnCell.Value;

                if (action == "STOP")
                {
                    btnCell.Value = "START";
                    gridDisplay.Rows[i].Cells["colStartStop"].Style.BackColor = Color.LightGreen;
                    gridDisplay.Rows[i].Cells["colStartStop"].Style.ForeColor = Color.Black;
                }
            }
        }
    }
}


The funny thing is that setting the Colors works fine but when I set the Value it runs extremely slow.

Can someone please explain what I'm doing wrong here.

Thank you,
-DA
Posted
Updated 28-Jun-12 19:33pm
v4

First of all, carry out of the loop the check info == "Hello word"; this is the invariant of the cycle, so you waste time on re-estimation of it. It can be optimized out, but it hurts my eyes to see such thing.

The problem I can see is hard-coded immediate constants of the string type, never a good idea, not good for maintenance. As to performance, it could be possible that indexing Cells with the string is not the fastest way of addressing a cell, because, like it or not, this is some kind of the search by a key. So, try to pre-fetch the column indices of this three cells: dataGrid.Rows[i].Cells["colHelloWorld"], dataGrid.Rows[i].Cells["colBackColor"] and dataGrid.Rows[i].Cells["colForeColor"]:
http://msdn.microsoft.com/en-us/library/system.windows.forms.datagridviewcell.columnindex.aspx[^].

In your case, all the cells under the loop will have three different column indices, repeating in all the iterations of the cycle, which are will repeat dataGrid.Rows.Count times. If you pre-fetch them, you can address the cells by index in all iterations except one:

C#
void ProcessData(string info) {
    int helloWorldColumnIndex = 0;
    int backColorColumnIndex = 0;
    int foreColorColumnIndex = 0;
    for (int i = 0; i < dataGrid.Rows.Count; ++i) {
        if (i == 0) {
            // using those "colHelloWorld" is also bad, but this is all I know from this code sample
            // in real code, use only helloWorldColumnIndex, backColorColumnIndex, foreColorColumnIndex,
            // have them known in advance...
            helloWorldColumnIndex = dataGrid.Rows[i].Cells["colHelloWorld"].ColumnIndex;
            backColorColumnIndex = dataGrid.Rows[i].Cells["colBackColor"].ColumnIndex;
            foreColorColumnIndex = dataGrid.Rows[i].Cells["colForeColor"].ColumnIndex;
        } //if first time
        var gridInfoCell = dataGrid.Rows[i].Cells[helloWorldColumnIndex];
        string gridInfo = (string)gridInfoCell.Value;
        if (gridInfo == info) {
            gridInfoCell.Value = "Good by, and don't hard-code immediate constants anymore!";
            dataGrid.Rows[i].Cells[backColorColumnIndex].Style.BackColor = Color.Red;
            dataGrid.Rows[i].Cells[ForeColorColumnIndex].Style.ForeColor = Color.White;
        } //if right info
    } //loop
} //ProcessData


Of course, this is not the best option, because you could determine the column indices in first place, when you set up the whole grid view. I only demonstrated the isolated solution, based only on your existing code and nothing else. Of course, you should not use those immediate string constants. I hope you got the idea.

Wonderfully, ++i instead of i++ gives better performance. (But rename this variable to
"index" or something. Never use single-character identifiers.)

[EDIT #1]

The code sample is modified according to last modification of the code sample in the text of the question by OP.

[EDIT #2]

However, these improvements are just pretty much pointless rat race. The whole approach is wrong. Radically, the only real key to grid view performance is its virtual mode. Please see:
http://msdn.microsoft.com/en-us/library/system.windows.forms.datagridview.virtualmode.aspx[^].

—SA
 
Share this answer
 
v6
Comments
d.allen101 28-Jun-12 19:36pm    
I accept your solution but I apologize, my example is incorrect. I have edited my example can you now take a look at it?
Sergey Alexandrovich Kryukov 28-Jun-12 21:28pm    
OK, modified accordingly, but the purpose was to give you the idea. You should do different thing: prepare those column indices in advance, when you set up the instance of the grid view; you don't have to calculate it in the cycle. I had no other information from you, so I've demonstrated how to pre-fetch indices in the first iteration of the cycle only.

By the way, it will be very nice of you if you make it working and then measure and report the expected improvement in performance.
To time things accurately, use the class System.Diagnostics.Stopwatch:
http://msdn.microsoft.com/en-us/library/system.diagnostics.stopwatch.aspx.

Good luck,
--SA
the solution is to set "AutoSizeMode = DataGridViewAutoSizeColumnMode.None".
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900