You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何快速向DataTable插入大量行并绑定至DataGridView

优化20万条数据插入DataTable并绑定DataGridView的方案

一、先关闭DataTable的事件与约束

DataTable默认会在新增行时触发各类事件(如RowChanged)、检查约束,这对批量插入是额外性能开销。可以先临时禁用,插入完成后恢复:

public static void InsertAutomaticDataRows<T>(this DataTable dataTable, IEnumerable<T> objects)
{
    var properties = typeof(T).GetProperties();
    // 保存原始状态
    var originalConstraintState = dataTable.EnforceConstraints;
    dataTable.BeginLoadData(); // 禁用通知、约束检查

    try
    {
        foreach (var obj in objects)
        {
            var row = dataTable.NewRow();
            foreach (var property in properties)
            {
                row[property.Name] = property.GetValue(obj) ?? DBNull.Value;
            }
            dataTable.Rows.Add(row);
        }
    }
    finally
    {
        dataTable.EndLoadData(); // 恢复通知与约束
        dataTable.EnforceConstraints = originalConstraintState;
    }
}

二、缓存反射委托替代重复GetValue

反射的GetValue调用本身较慢,提前把属性获取逻辑编译成委托缓存起来,避免循环里重复反射开销:

// 全局缓存属性获取委托
private static readonly Dictionary<Type, Dictionary<string, Func<object, object>>> _propertyGetterCache = new();

public static void InsertAutomaticDataRows<T>(this DataTable dataTable, IEnumerable<T> objects)
{
    var type = typeof(T);
    // 初始化并缓存委托
    if (!_propertyGetterCache.TryGetValue(type, out var getters))
    {
        getters = type.GetProperties()
            .ToDictionary(p => p.Name, p => 
            {
                var paramExpr = Expression.Parameter(typeof(object));
                var castExpr = Expression.Convert(paramExpr, type);
                var propAccessExpr = Expression.Property(castExpr, p);
                var resultExpr = Expression.Convert(propAccessExpr, typeof(object));
                return Expression.Lambda<Func<object, object>>(resultExpr, paramExpr).Compile();
            });
        _propertyGetterCache[type] = getters;
    }

    var originalConstraintState = dataTable.EnforceConstraints;
    dataTable.BeginLoadData();

    try
    {
        foreach (var obj in objects)
        {
            var row = dataTable.NewRow();
            foreach (var kvp in getters)
            {
                row[kvp.Key] = kvp.Value(obj) ?? DBNull.Value;
            }
            dataTable.Rows.Add(row);
        }
    }
    finally
    {
        dataTable.EndLoadData();
        dataTable.EnforceConstraints = originalConstraintState;
    }
}

三、跳过DataTable,直接绑定IEnumerable

如果不需要DataTable的额外功能,直接把数据源绑定到DataGridView能省去转换开销。同时开启虚拟模式优化大数据渲染:

// 开启虚拟模式
dataGridView1.VirtualMode = true;
var dataList = objects.ToList(); // 提前枚举避免重复计算
dataGridView1.DataSource = dataList;

// 绑定CellValueNeeded事件提供数据
dataGridView1.CellValueNeeded += (sender, e) =>
{
    var item = dataList[e.RowIndex];
    var property = typeof(T).GetProperties()[e.ColumnIndex];
    e.Value = property.GetValue(item) ?? DBNull.Value;
};

四、DataGridView绑定前暂停UI更新

绑定数据前先暂停控件布局更新,避免每新增一行就刷新UI:

// 暂停UI更新
dataGridView1.SuspendLayout();
dataGridView1.DataSource = null;

// 执行DataTable插入操作
yourDataTable.InsertAutomaticDataRows(yourObjects);

// 绑定并恢复UI
dataGridView1.DataSource = yourDataTable;
dataGridView1.ResumeLayout();

五、用LoadDataRow批量插入

将对象转换为值数组后,使用LoadDataRow方法插入,比逐行Add效率更高:

public static void InsertAutomaticDataRows<T>(this DataTable dataTable, IEnumerable<T> objects)
{
    var properties = typeof(T).GetProperties();
    var originalConstraintState = dataTable.EnforceConstraints;
    dataTable.BeginLoadData();

    try
    {
        foreach (var obj in objects)
        {
            var values = new object[properties.Length];
            for (int i = 0; i < properties.Length; i++)
            {
                values[i] = properties[i].GetValue(obj) ?? DBNull.Value;
            }
            dataTable.LoadDataRow(values, true);
        }
    }
    finally
    {
        dataTable.EndLoadData();
        dataTable.EnforceConstraints = originalConstraintState;
    }
}

内容的提问来源于stack exchange,提问作者Alireza Noori

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 03:55:28