我正在使用一个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 毫秒