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

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

private void ApplyColoring() { if (dataGridView1.DataSource != null) { foreach (DataGridViewRow dataGridRow in dataGridView1.Rows) { // hardmap a color to a column IDictionary colorDictionary = new Dictionary(); 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 checkedValues = new List(); // first we loop through all the rows foreach (DataGridViewRow gridRow in dataGridView1.Rows) { IDictionary checkedVal = new Dictionary(); // 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不闪烁(同时不丢失网格中的当前数据)。

两个建议:

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

你可以打开双缓冲。

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

干杯

我找到了另一种为慢数据网格做reflection双缓冲的方法:

使用一些reflection创建一个扩展方法,以在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); } } 

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

 this.dataGrid.DoubleBuffered(true); 

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

尝试在更新前调用SuspendLayout。 别忘了打电话给ResumeLayout。

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

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

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

无论何时更改单元格值,网格都会自动更新并更改背景颜色

打开双缓冲

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

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