如何防止数据网格中的行在应用程序运行时闪烁

发布于 2024-08-17 09:49:46 字数 3408 浏览 7 评论 0原文

在我目前正在开发的应用程序中,我使用 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 在执行新查询时不会闪烁(同时不会丢失网格中的当前数据)。

In the application I'm developing at the moment I'm using a datagridview to display data. To fill it, I've to press a button and a backgroundworker will start running, it will fill a datatable and when it's finished running it will use the datatable as the datasource for the datagrid. This works fine, the UI stays responsive et cetera.
But now I've implemented coloring to the rows, depending on their values (Im still playing around with it, so any suggestions are welcome):

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

This is giving me problems. Not because the coloring doesn't work, it does. But because it makes it hella slow. The first time it runs fine, but when i press the button again, it's slow as hell and the datagrid is flickering.
I want this run as postprocess, so it's (or rather should) be run after the backgroundworker is completed.
But when i call applycoloring from the RunWorkerCompleted event its just slow. What should I do to prvent this? How can I make sure the UI doesnt flicker while its executing a new query (while NOT LOSING the current data in the grid).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

年华零落成诗 2024-08-24 09:49:46

您可以打开双缓冲。

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

干杯

you can turn on double buffering.

VB:

Imports System.Reflection

put the following e.g. in 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)

For C#: go to:Fixing a slow scrolling DataGridView

Cheers

情绪操控生活 2024-08-24 09:49:46

两个建议:

  1. 尝试在循环之前调用 SuspendLayout() ,在循环之后调用 ResumeLayout() 。大多数其他控件调用此 BeginUpdate() 和 EndUpdate()(Listviews、Combobox 等)。
  2. 如果您正在处理大量数据,请在 DataGridView 上使用 VirtualMode
    数据。

Two suggestions:

  1. Try calling SuspendLayout() prior to the loop and ResumeLayout() after the loop. Most other controls call this BeginUpdate() and EndUpdate() (Listviews, Combobox's etc).
  2. Use VirtualMode on DataGridView if you're dealing with large amount of
    data.
梦明 2024-08-24 09:49:46

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

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

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 -DataGridView 中闪烁

I found another way to do the reflection double buffering for slow datagrids:

Create an extension method with some reflection to set double buffering on the datagrid:

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

Then in the form initializer do:

this.dataGrid.DoubleBuffered(true);

This is very similar to Evolved's answer and credits go to Shweta Lodha:
http://www.codeproject.com/Tips/390496/Reducing-flicker-blinking-in-DataGridView

不打扰别人 2024-08-24 09:49:46

打开双缓冲

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

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

Turn on double buffering

List of namespaces required for the function to compile is:

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

then initialize datagridview

dataGridView1.DoubleBuffered(true);
倾城月光淡如水﹏ 2024-08-24 09:49:46

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

Try to call SuspendLayout before your updates. Do not forget to call ResumeLayout.

挥剑断情 2024-08-24 09:49:46

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

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

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

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

I would highly recommend not to loop over the grid (double buffering might help but it is just "hiding" the real problem) since it produces a lot of rendering.

For purposes like this I use a eventhandler:

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

Anytime your cell values change your grid gets automatically updates and changes the back color

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文