向单元格赋值时,DataGridView SLOW [英] DataGridView SLOW when assigning value to cell

查看:97
本文介绍了向单元格赋值时,DataGridView SLOW的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我似乎无法弄清楚这里发生了什么...我有一个dataGridView,在任何给定时间不超过500行,但通常大约200或300.我遍历网格并设置按钮文本和颜色根据用户互动。例如:



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;
                }
            }
        }
    }
}





好​​笑事情是设置颜色工作正常,但当我设置它运行非常慢。



有人可以解释我在这里做错了什么。



谢谢,

-DA



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

推荐答案

首先,执行循环检查 info ==Hello word; 这是循环的不变量,所以你浪费时间重新估算它。它可以优化,但看到这样的事情会让我的眼睛受伤。



我能看到的问题是硬编码立即常数字符串类型,从来不是一个好主意,不利于维护。至于性能,使用字符串索引 Cells 可能不是解决单元格的最快方法,因为,无论喜欢与否,这都是某种形式的按键搜索。因此,尝试预取这三个单元格的列索引:dataGrid.Rows [i] .Cells [colHelloWorld],dataGrid.Rows [i] .Cells [colBackColor]和dataGrid.Rows [i]。单元格[colForeColor]:

http ://msdn.microsoft.com/en-us/library/system.windows.forms.datagridviewcell.columnindex.aspx [ ^ ]。



In在你的情况下,循环下的所有单元格将有三个不同的列索引,在循环的所有迭代中重复,这将重复 dataGrid.Rows.Count 次。如果你预先获取它们,你可以在所有迭代中通过索引寻址单元格,除了一个:



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:

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





当然,这不是最好的选择,因为你可以确定列索引首先,当您设置整个网格视图时。我只展示了孤立的解决方案,仅基于您现有的代码,而不是其他任何内容。当然,您不应该使用那些立即字符串常量。我希望你有这个主意。



很棒, ++ i 而不是 i ++ 提供更好的性能。 (但是将此变量重命名为

index 或者其他内容。切勿使用单字符标识符。)

< br $> b $ b



代码示例根据OP问题文本中代码示例的最后修改进行修改。







然而,这些改进只是非常无意义的争吵。整个方法都是错误的。从根本上说,网格视图性能的唯一真正关键是虚拟模式。请参阅:

http:// msdn .microsoft.com / zh-cn / library / system.windows.forms.datagridview.virtualmode.aspx [ ^ ]。



-SA



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.)



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



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


解决方案是设置AutoSizeMode = DataGridViewAutoSizeColumnMode.None。
the solution is to set "AutoSizeMode = DataGridViewAutoSizeColumnMode.None".


这篇关于向单元格赋值时,DataGridView SLOW的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆