我正在使用一个BindingSource控件(参考这里)来填充我的DataGridView控件。上面有大约 1000 多条记录。我正在使用线程来做到这一点。在这种情况下,DataGridView 的执行速度非常慢。
我试图将DoubleBuffered属性设置为 true、RowHeadersWidthSizeMode禁用、AutoSizeColumnsMode无。但仍然是相同的行为。
请在这方面帮助我。如何提高网格的性能。
在此先感谢,
维杰
我正在使用一个BindingSource控件(参考这里)来填充我的DataGridView控件。上面有大约 1000 多条记录。我正在使用线程来做到这一点。在这种情况下,DataGridView 的执行速度非常慢。
我试图将DoubleBuffered属性设置为 true、RowHeadersWidthSizeMode禁用、AutoSizeColumnsMode无。但仍然是相同的行为。
请在这方面帮助我。如何提高网格的性能。
在此先感谢,
维杰
如果您有大量的行,例如 10,000 或更多,为了避免性能泄漏 - 在数据绑定之前执行以下操作:
dataGridView1.RowHeadersWidthSizeMode = DataGridViewRowHeadersWidthSizeMode.EnableResizing;
// or even better, use .DisableResizing. Most time consuming enum is DataGridViewRowHeadersWidthSizeMode.AutoSizeToAllHeaders
// set it to false if not needed
dataGridView1.RowHeadersVisible = false;
数据绑定后,您可以重新启用它。
确保你不自动调整列大小,它可以提高性能。
即不要这样做:
Datagridview.Columns[I].AutoSizeMode = DataGridViewAutoSizeColumnMode.xxxxx;
通常关闭自动调整大小和双缓冲有助于加快 DataGridView 的填充。检查DGV双缓冲是否开启正常:
if (!System.Windows.Forms.SystemInformation.TerminalServerSession)
{
Type dgvType = dataGridView1.GetType();
PropertyInfo pi = dgvType.GetProperty("DoubleBuffered",
BindingFlags.Instance | BindingFlags.NonPublic);
pi.SetValue(dataGridView1, value, null);
}
使用 WinAPI WM_SETREDRAW消息禁用重绘也有帮助:
// *** API Declarations ***
[DllImport("user32.dll")]
private static extern int SendMessage(IntPtr hWnd, Int32 wMsg, bool wParam, Int32 lParam);
private const int WM_SETREDRAW = 11;
// *** DataGridView population ***
SendMessage(dataGridView1.Handle, WM_SETREDRAW, false, 0);
// Add rows to DGV here
SendMessage(dataGridView1.Handle, WM_SETREDRAW, true, 0);
dataGridView1.Refresh();
如果您不需要 2 路数据绑定或 BindingSource 提供的某些功能(过滤等),您可以考虑使用DataGridView.Rows.AddRange()方法一次性添加行。
带有示例的源文章的链接:http: //10tec.com/articles/why-datagridview-slow.aspx
我知道我参加聚会迟到了,但我最近厌倦了 DataGridView 控件的自动调整大小有多慢,并且觉得某个地方的某个人可能会从我的解决方案中受益。
我创建了这个扩展方法来手动测量和调整 DataGridView 中的列。将AutoSizeColumnsMode设置为DataGridViewAutoSizeColumnsMode.None并在设置 DataSource 后调用此方法。
/// <summary>
/// Provides very fast and basic column sizing for large data sets.
/// </summary>
public static void FastAutoSizeColumns(this DataGridView targetGrid)
{
// Cast out a DataTable from the target grid datasource.
// We need to iterate through all the data in the grid and a DataTable supports enumeration.
var gridTable = (DataTable)targetGrid.DataSource;
// Create a graphics object from the target grid. Used for measuring text size.
using (var gfx = targetGrid.CreateGraphics())
{
// Iterate through the columns.
for (int i = 0; i < gridTable.Columns.Count; i++)
{
// Leverage Linq enumerator to rapidly collect all the rows into a string array, making sure to exclude null values.
string[] colStringCollection = gridTable.AsEnumerable().Where(r => r.Field<object>(i) != null).Select(r => r.Field<object>(i).ToString()).ToArray();
// Sort the string array by string lengths.
colStringCollection = colStringCollection.OrderBy((x) => x.Length).ToArray();
// Get the last and longest string in the array.
string longestColString = colStringCollection.Last();
// Use the graphics object to measure the string size.
var colWidth = gfx.MeasureString(longestColString, targetGrid.Font);
// If the calculated width is larger than the column header width, set the new column width.
if (colWidth.Width > targetGrid.Columns[i].HeaderCell.Size.Width)
{
targetGrid.Columns[i].Width = (int)colWidth.Width;
}
else // Otherwise, set the column width to the header width.
{
targetGrid.Columns[i].Width = targetGrid.Columns[i].HeaderCell.Size.Width;
}
}
}
}
虽然我绝对不会推荐使用 1000+ 行填充 DGV,但这种方法会带来巨大的性能优势,同时产生与AutoResizeColumns方法非常相似的结果。
对于 10k 行:(10K 行 * 12 列。)
AutoResizeColumns = ~3000 毫秒
FastAutoSizeColumns = ~140 毫秒
我不得不在一些地方禁用自动调整大小才能看到性能的最大改进。AutoSizeRowsMode就我而言,我为、AutoSizeColumnsMode和启用了自动调整大小模式ColumnHeadersHeightSizeMode。所以在将数据绑定到DataGridView:
dataGridView.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.None;
dataGridView.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.None;
dataGridView.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.DisableResizing;
// ... Bind the data here ...
// Set the DataGridView auto-size modes back to their original settings.
dataGridView.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.AllCells;
dataGridView.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCells;
dataGridView.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.AutoSize;
如果您不想覆盖 DataGridView 的虚拟模式所需的方法,如果您可以考虑使用 Listview,还有另一种选择:
http://www.codeproject.com/Articles/16009/A-Much-Easier-to-Use-ListView
- 它有一个版本(FastObjectListView),可以在不到 0.1 秒的时间内构建一个包含 100,000 个对象的列表。
- 它有一个版本(DataListView)支持数据绑定,另一个版本(FastDataListView)支持大型(100,000+)数据集的数据绑定。
当用户加载 10000 个项目或对它们进行排序时,我遇到了性能问题。当我评论行时:
this.dataEvents.AutoSizeRowsMode = System.Windows.Forms.DataGridViewAutoSizeRowsMode.AllCells;
一切都变得很好。
@Bobby L 的回答很棒,但会阻塞 UI 线程。这是我的改编,它在将计算值应用于 UI 线程之前计算 BackgroundWorker 中列的宽度
public partial class Form1 : Form
{
private BackgroundWorker _worker;
public Form1()
{
InitializeComponent();
_worker = new BackgroundWorker();
_worker.DoWork += _worker_DoWork;
_worker.RunWorkerCompleted += _worker_RunWorkerCompleted;
}
private void _worker_DoWork(object sender, DoWorkEventArgs e)
{
e.Result = GetAutoSizeColumnsWidth(dataGridView1);
}
private void _worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
SetAutoSizeColumnsWidth(dataGridView1, (int[])e.Result);
}
private int[] GetAutoSizeColumnsWidth(DataGridView grid)
{
var src = ((IEnumerable)grid.DataSource)
.Cast<object>()
.Select(x => x.GetType()
.GetProperties()
.Select(p => p.GetValue(x, null)?.ToString() ?? string.Empty)
.ToArray()
);
int[] widths = new int[grid.Columns.Count];
// Iterate through the columns.
for (int i = 0; i < grid.Columns.Count; i++)
{
// Leverage Linq enumerator to rapidly collect all the rows into a string array, making sure to exclude null values.
string[] colStringCollection = src.Where(r => r[i] != null).Select(r => r[i].ToString()).ToArray();
// Sort the string array by string lengths.
colStringCollection = colStringCollection.OrderBy((x) => x.Length).ToArray();
// Get the last and longest string in the array.
string longestColString = colStringCollection.Last();
// Use the graphics object to measure the string size.
var colWidth = TextRenderer.MeasureText(longestColString, grid.Font);
// If the calculated width is larger than the column header width, set the new column width.
if (colWidth.Width > grid.Columns[i].HeaderCell.Size.Width)
{
widths[i] = (int)colWidth.Width;
}
else // Otherwise, set the column width to the header width.
{
widths[i] = grid.Columns[i].HeaderCell.Size.Width;
}
}
return widths;
}
public void SetAutoSizeColumnsWidth(DataGridView grid, int[] widths)
{
for (int i = 0; i < grid.Columns.Count; i++)
{
grid.Columns[i].Width = widths[i];
}
}
}
这解决了我的问题:
for (int z = 0; z < dataGridView1.Columns.Count; z++)
{
dataGridView1.Columns[z].AutoSizeMode = DataGridViewAutoSizeColumnMode.None;
}
... Code where I change the content of dataGridView1 in a loop ...
for (int z = 0; z < dataGridView1.Columns.Count; z++)
{
dataGridView1.Columns[z].AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells;
}
我认为您需要考虑在虚拟模式下使用数据网格。基本上,您预先设置网格的范围,然后根据需要覆盖“OnCellValueNeeded”。
您应该会发现(尤其是对于只有 1000 左右的行)您的网格填充变得有效即时。
祝你好运,
我有同样的问题,我通过设置解决了
AutoSizeRowsMode to DisplayedCellsExceptHeaders
并为列设置相同
经过一段时间的故障排除后,我发现速度的主要问题仍然来自于从非 UI 线程更改 dataGridView。下面的代码完全解决了我从dataTable数据源缓慢填充的datagridview
dataGridView1.Invoke(new MethodInvoker(() =>
dataGridView1.DataSource = table)
);
Dim asrm = DataGridView1.AutoSizeRowsMode
Dim ascm = DataGridView1.AutoSizeColumnsMode
Dim chhs = DataGridView1.ColumnHeadersHeightSizeMode
DataGridView1.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.None
DataGridView1.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.None
DataGridView1.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.DisableResizing
DataGridView1.SuspendLayout()
bs.SuspendBinding()
DataGridView1.DataSource = Nothing
For Each t As obj In lt_list
bs.Add(t)
Next
DataGridView1.DataSource = bs
DataGridView1.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.DisplayedCellsExceptHeaders
DataGridView1.AutoSizeColumnsMode = ascm
DataGridView1.ColumnHeadersHeightSizeMode = chhs
bs.ResumeBinding()
DataGridView1.ResumeLayout()
16000 个项目,.DataSource <> Nothing 时 16 秒,.DataSource = Nothing 时 300 毫秒