6

在我正在开发的应用程序中,我正在使用 datagridview 来显示数据。要填充它,我必须按下一个按钮,后台工作程序将开始运行,它将填充一个数据表,当它完成运行时,它将使用数据表作为数据网格的数据源。这工作正常,用户界面保持响应等等。但是现在我已经根据它们的值实现了对行的着色(我还在玩它,所以欢迎提出任何建议):

        private void ApplyColoring()
    {
        if (dataGridView1.DataSource != null)
        {
            foreach (DataGridViewRow dataGridRow in dataGridView1.Rows)
            {
                // hardmap a color to a column
                IDictionary<Int32, Color> colorDictionary = new Dictionary<Int32, Color>();
                colorDictionary.Add( 7, Color.FromArgb(194, 235, 211));
                colorDictionary.Add( 8, Color.Salmon);
                colorDictionary.Add( 9, Color.LightBlue);
                colorDictionary.Add(10, Color.LightYellow);
                colorDictionary.Add(11, Color.LightGreen);
                colorDictionary.Add(12, Color.LightCoral);
                colorDictionary.Add(13, Color.Blue);
                colorDictionary.Add(14, Color.Yellow);
                colorDictionary.Add(15, Color.Green);
                colorDictionary.Add(16, Color.White);

                foreach (DataGridViewRow gridRow in dataGridView1.Rows)
                {
                    foreach (DataGridViewCell cell in gridRow.Cells)
                    {
                        if (colorDictionary.Keys.Contains(cell.ColumnIndex))
                        {
                            // standard background 
                            cell.Style.BackColor = Color.FromArgb(194, 235, 211);
                        }
                    }
                }

                IList<String> checkedValues = new List<String>();


                // first we loop through all the rows
                foreach (DataGridViewRow gridRow in dataGridView1.Rows)
                {
                    IDictionary<String, Int32> checkedVal = new Dictionary<String, Int32>();

                    // then we loop through all the data columns
                    int maxCol = dnsList.Count + 7;
                    for (int columnLoop = 7; columnLoop < maxCol; columnLoop++)
                    {
                        string current = gridRow.Cells[columnLoop].Value.ToString();

                        for (int checkLoop = 7; checkLoop < maxCol; checkLoop++)
                        {
                            string check = gridRow.Cells[checkLoop].Value.ToString();

                            if (!current.Equals(check))
                            {
                                if (checkedVal.Keys.Contains(current))
                                {
                                    gridRow.Cells[columnLoop].Style.BackColor = colorDictionary[checkedVal[current]];
                                }
                                else
                                {
                                    gridRow.Cells[columnLoop].Style.BackColor = colorDictionary[columnLoop];
                                    checkedVal.Add(current, columnLoop);
                                }
                            }
                        }
                    }
                }
            }
        }
    }

这给我带来了问题。不是因为着色不起作用,而是它起作用。但是因为它让它变慢了。第一次运行良好,但是当我再次按下按钮时,速度慢得要命,数据网格在闪烁。我希望这个作为后处理运行,所以它(或者更确切地说应该)在后台工作完成后运行。但是当我从 RunWorkerCompleted 事件中调用 applycoloring 时,它只是很慢。我应该怎么做才能防止这种情况?如何确保 UI 在执行新查询时不会闪烁(同时不会丢失网格中的当前数据)。

4

6 回答 6

19

您可以打开双缓冲。

VB:

Imports System.Reflection

将以下内容放入 Form_Load

Dim systemType As Type = DataGridView1.GetType()
Dim propertyInfo As PropertyInfo = systemType.GetProperty("DoubleBuffered", BindingFlags.Instance Or BindingFlags.NonPublic)
propertyInfo.SetValue(DataGridView1, True, Nothing)

对于 C#:转到:修复缓慢滚动的 DataGridView

干杯

于 2011-07-22T13:04:39.217 回答
6

两个建议:

  1. 尝试在循环之前调用 SuspendLayout() 并在循环之后调用 ResumeLayout()。大多数其他控件将此称为 BeginUpdate() 和 EndUpdate()(列表视图、组合框等)。
  2. 如果您要处理大量数据,请在 DataGridView 上使用 VirtualMode。
于 2010-01-11T12:44:26.043 回答
6

我找到了另一种为慢速数据网格进行反射双缓冲的方法:

创建一个带有一些反射的扩展方法以在数据网格上设置双缓冲:

public static class DataGridViewExtensioncs
{

    public static void DoubleBuffered(this DataGridView dgv, bool setting)
    {
        var dgvType = dgv.GetType();
        var pi = dgvType.GetProperty("DoubleBuffered",
              BindingFlags.Instance | BindingFlags.NonPublic);
        pi.SetValue(dgv, setting, null);
    }
}

然后在表单初始化器中执行:

this.dataGrid.DoubleBuffered(true);

这与 Evolved 的答案非常相似,并且归功于 Shweta Lodha: http: //www.codeproject.com/Tips/390496/Reducing-flicker-blinking-in-DataGridView

于 2014-08-11T10:07:49.670 回答
2

开启双缓冲

编译函数所需的命名空间列表是:

using System;
using System.Reflection;
using System.Windows.Forms;

public static class ExtensionMethods
{
   public static void DoubleBuffered(this DataGridView dgv, bool setting)
   {
      Type dgvType = dgv.GetType();
      PropertyInfo pi = dgvType.GetProperty("DoubleBuffered", BindingFlags.Instance | BindingFlags.NonPublic);
      pi.SetValue(dgv, setting, null);
   }
}

然后初始化datagridview

dataGridView1.DoubleBuffered(true);
于 2017-06-26T00:30:31.347 回答
1

尝试在更新之前调用 SuspendLayout。不要忘记调用 ResumeLayout。

于 2010-01-11T12:46:07.587 回答
1

我强烈建议不要在网格上循环(双缓冲可能会有所帮助,但它只是“隐藏”真正的问题),因为它会产生大量渲染。

出于这样的目的,我使用事件处理程序:

dataGridView1.CellValueChanged += new DataGridViewCellEventHandler(dataGridView1_CellValueChanged);

private void dataGridView1_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
    {
            if (dataGridView1.Columns[5].Index == e.ColumnIndex && e.RowIndex >= 0 && dataGridView1[5, e.RowIndex].Value.ToString() != "0")
            {
                e.CellStyle.BackColor = Color.PaleGreen;
            }
    }

每当您的单元格值更改时,您的网格都会自动更新并更改背景颜色

于 2016-08-05T09:08:19.587 回答